BSOJ3866题解

成为了口胡大师,以后还要继续努力!

首先强制所有节点选择白色,获得 \(\sum w_i\) 的权值。

接下来定义选择一个节点相当于将该节点染黑。容易发现选择一个节点应该获得 \(b_i-w_i-p_i\) 的权值。

但是如果这个位置和满足 \(1\leq j<i,l_i\leq a_j\leq r_i\)\(j\) 都被同时选择了,应该返还 \(p_i\) 的权值。

题目变成了同时选择若干个节点能够获得某些权值,需要最大化权值之和。

容易变成最大权闭合子图。设题目相当于告诉你同时选择集合为 \(S_i\) 的点集能够获得 \(v_i\) 的权值。

首先对每个集合建立一个点 \(s_i\)\(s_i\) 拥有 \(v_i\) 的权值,然后令 \(s_i\) 连接其包含的元素即可。

对于每个元素,自身权值为 \(b_i-w_i-p_i\)

然后所有元素连接一个汇点即可。因为 \(p_i\geq 0\) 不选白不选,一定是正确的。

#include<algorithm>
#include<cstdio>
#include<cctype>
const int M=20005,INF=998244353;
int n,ege=1,tot,s,t,A[M],B[M],a[M],l[M],r[M],x[M],y[M],p[M];int len,lsh[M];
int cur[M*50],h[M*50],d[M*50],id[M*50];int L,R,q[M*50];
struct Edge{
	int v,flow,nx;
}e[M*50];
inline int min(const int&a,const int&b){
	return a>b?b:a;
}
inline void Add(const int&u,const int&v,const int&flow){
	e[++ege]=(Edge){v,flow,h[u]};h[u]=ege;
	e[++ege]=(Edge){u,0,h[v]};h[v]=ege;
}
inline void Build(const int&u,const int&L=1,const int&R=len){
	id[u]=++tot;if(L==R)return;
	const int&mid=L+R>>1;Build(u<<1,L,mid);Build(u<<1|1,mid+1,R);Add(id[u],id[u<<1],INF);Add(id[u],id[u<<1|1],INF);
}
inline void Ins(const int&u,const int&v,const int&x,const int&L=1,const int&R=len){
	Add(++tot,id[u],INF);Add(id[u]=tot,v,INF);if(L==R)return;const int&mid=L+R>>1;
	x<=mid?Ins(u<<1,v,x,L,mid):Ins(u<<1|1,v,x,mid+1,R);Add(id[u],id[u<<1],INF);Add(id[u],id[u<<1|1],INF);
}
inline void Link(const int&u,const int&v,const int&l,const int&r,const int&L=1,const int&R=len){
	if(l>R||L>r)return;if(l<=L&&R<=r)return void(id[u]&&(Add(v,id[u],INF),0));
	const int&mid=L+R>>1;Link(u<<1,v,l,r,L,mid);Link(u<<1|1,v,l,r,mid+1,R);
}
inline bool BFS(){
	for(int u=0;u<=tot;++u)d[u]=-1;d[q[L=R=1]=s]=0;
	while(L<=R){
		const int&u=q[L++];if(u==t)return true;
		for(int v,E=cur[u]=h[u];E;E=e[E].nx)if(e[E].flow&&!~d[v=e[E].v])d[q[++R]=v]=d[u]+1;
	}
	return false;
}
inline int DFS(const int&u,const int&flow){
	if(u==t)return flow;
	int used(flow);
	for(int v,&E=cur[u];E;E=e[E].nx)if(e[E].flow&&d[u]+1==d[v=e[E].v]){
		const int&F=DFS(v,min(used,e[E].flow));if(!F)d[v]=-1;
		used-=F;e[E].flow-=F;e[E^1].flow+=F;if(!used)return flow;
	}
	return flow-used;
}
inline int Dinic(){
	int ans(0);while(BFS())while(const int&F=DFS(s,INF))ans+=F;return ans;
}
inline int read(){
	int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
signed main(){
	int sum(0),S(0);n=read();s=0;t=++tot;for(int i=1;i<=n;++i)A[i]=++tot,B[i]=++tot;
	for(int i=1;i<=n;++i)a[i]=read(),x[i]=read(),y[i]=read(),l[i]=read(),r[i]=read(),p[i]=read(),sum+=y[i];
	for(int i=1;i<=n;++i)lsh[++len]=a[i];std::sort(lsh+1,lsh+len+1);len=std::unique(lsh+1,lsh+len+1)-lsh-1;
	for(int i=1;i<=n;++i){
		a[i]=std::lower_bound(lsh+1,lsh+len+1,a[i])-lsh;
		l[i]=std::lower_bound(lsh+1,lsh+len+1,l[i])-lsh;
		r[i]=std::lower_bound(lsh+1,lsh+len+1,r[i]+1)-lsh-1;
	}
	for(int i=1;i<=n;++i){
		Add(s,A[i],p[i]);S+=p[i];
		if(x[i]-y[i]-p[i]>0)S+=x[i]-y[i]-p[i],Add(s,B[i],x[i]-y[i]-p[i]);else Add(B[i],t,p[i]+y[i]-x[i]);
		Link(1,A[i],l[i],r[i]);Add(A[i],B[i],INF);Ins(1,B[i],a[i]);
	}
	printf("%d",S-Dinic()+sum);
}
posted @ 2022-06-15 15:53  Prean  阅读(32)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};