bzoj3218 a+b Problem(最小割+主席树优化建边)
由于6.22博主要学测,大半时间学文化课,近期刷题量&写题解的数量会急剧下降。
这题出得挺经典的,首先一眼最小割,考虑朴素的做法:与S联通表示白色,与T联通表示黑色,S向i连流量为w[i]的边,i向T连流量为b[i]的边,然后i'向i连容量为p[i]的边,所有满足条件的j向i'连一条容量为无穷大的边(只要满足其一就要割掉)。然后边数显然不合法,一眼线段树优化,然而发现线段树无法连边,考虑主席树连边,对原序列建主席树,每个点的区间对应主席树上的O(logn)个节点,然后连接容量为无穷大的边即可。
#include<bits/stdc++.h> using namespace std; const int N=2e5+7,M=1e6+7,inf=1e9; struct edge{int x,id;}e[N]; int n,m,ecnt,tot,T,ans,mx; int L[N],R[N],val[N],seq[N],hd[N],v[M],w[M],nxt[M],q[N],lv[N],lc[N],rc[N],root[N],cnt[N]; void adde(int x,int y,int z) { v[++ecnt]=y,w[ecnt]=z,nxt[ecnt]=hd[x],hd[x]=ecnt; v[++ecnt]=x,w[ecnt]=0,nxt[ecnt]=hd[y],hd[y]=ecnt; } int findl(int x) { int l=1,r=mx,ans=mx; while(l<=r) { int mid=l+r>>1; if(seq[mid]>=x)ans=mid,r=mid-1;else l=mid+1; } return ans; } int findr(int x) { int l=1,r=mx,ans=1; while(l<=r) { int mid=l+r>>1; if(seq[mid]<=x)ans=mid,l=mid+1;else r=mid-1; } return ans; } int update(int prt,int l,int r,int i) { int rt=++tot; if(l==r)lc[rt]=rc[rt]=0,cnt[rt]=cnt[prt]+1; else{ int mid=l+r>>1; if(val[i]<=mid)lc[rt]=update(lc[prt],l,mid,i),rc[rt]=rc[prt]; else rc[rt]=update(rc[prt],mid+1,r,i),lc[rt]=lc[prt]; cnt[rt]=cnt[lc[rt]]+cnt[rc[rt]]; } adde(i,2*n+1+rt,inf); adde(2*n+1+prt,2*n+1+rt,inf); return rt; } void query(int rt,int l,int r,int i) { if(!cnt[rt])return; if(L[i]<=l&&r<=R[i]){adde(2*n+1+rt,n+i,inf);return;} int mid=l+r>>1; if(L[i]<=mid)query(lc[rt],l,mid,i); if(R[i]>mid)query(rc[rt],mid+1,r,i); } bool bfs() { memset(lv,-1,sizeof lv); int qs=0,qe=1; q[0]=lv[0]=0; while(qs<qe) { int u=q[qs++]; for(int i=hd[u];i;i=nxt[i])if(w[i]&&lv[v[i]]==-1)lv[v[i]]=lv[u]+1,q[qe++]=v[i]; } if(lv[T]==-1)return 0; return 1; } int dfs(int u,int low) { if(u==T||!low)return low; int sum=0; for(int i=hd[u];i;i=nxt[i]) if(w[i]&&lv[v[i]]==lv[u]+1) { int tmp=dfs(v[i],min(low,w[i])); w[i]-=tmp,w[i^1]+=tmp,low-=tmp,sum+=tmp; if(!low)return sum; } if(low)lv[u]=-1; return sum; } bool cmp(edge x,edge y){return x.x<y.x;} int main() { scanf("%d",&n); ecnt=1,T=1e5; for(int i=1,b,w,p;i<=n;i++) { scanf("%d%d%d%d%d%d",&e[i].x,&b,&w,&L[i],&R[i],&p); e[i].id=i,ans+=b+w,adde(0,i,w),adde(i,T,b),adde(n+i,i,p); } sort(e+1,e+n+1,cmp); mx=val[e[1].id]=1,seq[1]=e[1].x; for(int i=2;i<=n;i++) if(e[i].x==e[i-1].x)val[e[i].id]=mx;else val[e[i].id]=++mx,seq[mx]=e[i].x; for(int i=1;i<=n;i++) { L[i]=findl(L[i]),R[i]=findr(R[i]); root[i]=update(root[i-1],1,mx,i),query(root[i-1],1,mx,i); } while(bfs())ans-=dfs(0,inf); printf("%d",ans); }