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);
}