[BZOJ3218]a + b Problem-[主席树+网络流-最小割]
Description
Solution
此处我们按最小割的思路考虑。
暴力:S->i表示该点选黑色的权值b[i];i->T表示该点选白色的权值w[i]。考虑如果某个点i受点j为白点的影响,则将点i连向点j,边权为p[i]。但这么做假如有多个点j,p[i]就会被算多次。可以将i点拆为i和i'。则将i'连向j,边权为inf(即该边不能割),将i连向i',边权为p[i]。
不过这么搞肯定要爆。考虑一下怎么优化。
我们发现最耗空间的是i'->j的边。(如果l[i],r[i]给的范围大的话空间简直。。em)。然后由于是点->区间,考虑线段树一类的知识点。显然主席树是可以的。
主席树下标按照a的大小。
我们从左到右把点i加进去(a[i],l[i],r[i]要离散化),在主席树里找区间[l[i],r[i]]直接连边;然后将i点连向主席树内所有(存储区间包含a[i]的)节点。因为可能在主席树的某个节点下挂了一堆的点(即很多点i的a[i]相等),我们将主席树新建的节点向之前的节点连边。
由于各个点i已经向所有包含它们的主席树节点连边,主席树的节点间无需再连边了。
主席树相关的各种边边权都为inf。
然后就ok啦啦啦。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; const int inf=1e9; int n,m,k; int h[500010],tot; struct pas{int x,y,nxt,w,op,cost;}g[1000100]; int dep[500020],S,T; queue<int>q; struct DINIC{ bool bfs() { int x; memset(dep,0,sizeof(dep));dep[S]=1; while (!q.empty()) q.pop(); q.push(S); while (!q.empty()) { x=q.front();q.pop(); for (int i=h[x];i;i=g[i].nxt) if (!dep[g[i].y]&&g[i].w) { dep[g[i].y]=dep[x]+1; q.push(g[i].y); if (g[i].y==T) return 1; } } return 0; } int dfs(int x,int flow) { if (x==T||(!flow))return flow; int temp=0,js; for (int i=h[x];i;i=g[i].nxt) if (dep[g[i].y]==dep[x]+1&&g[i].w) { js=dfs(g[i].y,min(flow,g[i].w)); if (js) { g[i].w-=js; g[g[i].op].w+=js; temp+=js; flow-=js; if (!flow) return temp; } } if (!temp) dep[x]=0; return temp; } int dinic() { int ans=0; while (bfs()) ans+=dfs(S,inf); return ans; } }D; void add(int x,int y,int w) { g[++tot].x=x;g[tot].y=y;g[tot].w=w;g[tot].nxt=h[x];g[tot].op=tot+1;h[x]=tot; g[++tot].x=y;g[tot].y=x;g[tot].w=0;g[tot].nxt=h[y];g[tot].op=tot-1;h[y]=tot; } int a[5010],b[5010],w[5010],l[5010],r[5010],p[5010],hehe[5010]; int lc[500010],rc[500010],cnt,rt; void query(int k,int l,int r,int askx,int asky,int p) { if (!k) return; if (askx<=l&&r<=asky) { add(p,k,inf); return; } int mid=(l+r)/2;if (askx<=mid) query(lc[k],l,mid,askx,asky,p); if (asky>mid) query(rc[k],mid+1,r,askx,asky,p); } int modify(int k,int l,int r,int id,int x) { int o=++cnt;lc[o]=lc[k];rc[o]=rc[k]; if (k) add(o,k,inf); add(o,x,inf); if (l==r) return o; int mid=(l+r)/2; if (id<=mid) lc[o]=modify(lc[o],l,mid,id,x);else rc[o]=modify(rc[o],mid+1,r,id,x); return o; } int sum=0; int main() { scanf("%d",&n);cnt=2*n+1; S=0;T=2*n+1; for (int i=1;i<=n;i++) { scanf("%d%d%d%d%d%d",&a[i],&b[i],&w[i],&l[i],&r[i],&p[i]); sum+=w[i]+b[i]; hehe[i]=a[i]; add(S,i,b[i]);add(i,T,w[i]);add(i,n+i,p[i]); } sort(hehe+1,hehe+n+1); for (int i=1;i<=n;i++) { a[i]=lower_bound(hehe+1,hehe+n+1,a[i])-hehe; l[i]=lower_bound(hehe+1,hehe+n+1,l[i])-hehe; r[i]=upper_bound(hehe+1,hehe+n+1,r[i])-hehe-1; if (l[i]<=r[i]) query(rt,1,n,l[i],r[i],n+i); rt=modify(rt,1,n,a[i],i); } cout<<sum-D.dinic(); }