BZOJ3218 a+b Problem
这样复杂的限制条件显然是一道网络流题,考虑建图完成最小割。
难点在于不同的点黑白相互制约,假设没有这一限制,建图很显然。
设源点$S$,汇点$T$,对于第$i$个点:
·从$S$出发向$i$连容量为$b_i$的边。
·从$i$出发向$T$连容量为$w_i$的边。
如何加入$p_i$的限制呢?
对于一个点$i$,和所有满足$1\leq j<i,l_i\leq a_j\leq r_i$的$j$。
当$p_i$要被割掉,当且仅当存在$w_j$没有被割掉且$b_i$没被割掉。
因此对于$i$要确保有一条$b_i\space\rightarrow\space p_i\space\rightarrow\space w_j$的边。
所以对于每个点$i$设值一个新点$i'$,从$i$向$i'$连一条容量为$p_i$的边。
对于$i$的每一个$j$,从$i'$向$j$链接一条容量为正无穷的边。
由于$n$达到了$5000$,所以我们要考虑使用主席树优化建图。
其实很简单,就是把主席上的每个节点连向左右儿子,对于值域为$[a_i,a_i]$叶子节点连向$a_i$对应节点的$i$。
每次插入数之前,将$i'$连向主席上的$[l_i,r_i]$的区间,这样点数边数均在$n\space log(n)$级别。
然而为什么我的代码跑的这么慢啊。
哪位大佬来教教我网络流怎么写啊啊啊啊啊。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define M 600020 #define N 10010 #define INF 2000000020 #define mid (l+r>>1) using namespace std; int read(){ int nm=0,fh=1;char cw=getchar(); for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh; for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return nm*fh; } int n,m,fs[M],nt[M],to[M],r[M],cnt,ans,vis[M]; int A[N],B[N],W[N],ls[N],rs[N],P[N],S,T,tot; int L[M],R[M],rt[M],tmp,cur[M],q[M],hd,tl; struct Q{int kd,ps,nw;}sq[M]; bool cmp(Q i,Q j){return i.nw==j.nw?i.kd<j.kd:i.nw<j.nw;} inline void addedge(int x,int y,int rem){ nt[tmp]=fs[x],fs[x]=tmp,to[tmp]=y,r[tmp++]=rem; nt[tmp]=fs[y],fs[y]=tmp,to[tmp]=x,r[tmp++]=0; } void update(int x,int l,int r,int LS,int RS,int node){ if(RS<l||r<LS||x==0) return; if(LS<=l&&r<=RS) return addedge(node,x,INF); update(L[x],l,mid,LS,RS,node); update(R[x],mid+1,r,LS,RS,node); } void ins(int &x,int pre,int l,int r,int pos,int node){ x=++cnt,L[x]=L[pre],R[x]=R[pre]; if(l==r) return addedge(x,node,INF); //注意这里是因为在离散化时保证了每个ai,li,ri互不相同 //否则可能会出现ai相同的情况,需要特判 //if(l==r&&pre>0) addedge(x,pre,INF) if(pos<=mid) ins(L[x],L[pre],l,mid,pos,node); else ins(R[x],R[pre],mid+1,r,pos,node); if(L[x]) addedge(x,L[x],INF); if(R[x]) addedge(x,R[x],INF); } bool BFS(){ for(int i=1;i<=cnt;i++) vis[i]=-1; hd=tl=0,vis[S]=1,q[tl++]=S,cur[S]=fs[S]; while(hd<tl){ int x=q[hd++]; for(int i=fs[x];i!=-1;i=nt[i]){ if(vis[to[i]]>0||r[i]==0) continue; vis[to[i]]=vis[x]+1,q[tl++]=to[i]; cur[to[i]]=fs[to[i]]; } } return vis[T]>0; } int DFS(int x,int mxf){ if(x==T||mxf==0) return mxf; int temp=0; for(int &i=cur[x];i!=-1;i=nt[i]){ if(r[i]==0||vis[to[i]]!=vis[x]+1) continue; int rc=DFS(to[i],min(r[i],mxf-temp)); temp+=rc,r[i]-=rc,r[i^1]+=rc; if(temp==mxf) break; } if(temp==0) vis[x]=-1; return temp; } inline void DINIC(){for(;BFS();ans-=DFS(S,INF));} int main(){ n=read(),S=(n<<1),S++,T=S,T++,cnt=T; memset(fs,-1,sizeof(fs)); for(int i=1;i<=n;i++){ A[i]=read(),B[i]=read(),W[i]=read(); ls[i]=read(),rs[i]=read(),P[i]=read(); ans+=B[i]+W[i],addedge(i,i+n,P[i]); addedge(S,i,B[i]),addedge(i,T,W[i]); tot++,sq[tot].kd=0,sq[tot].ps=i,sq[tot].nw=ls[i]; tot++,sq[tot].kd=1,sq[tot].ps=i,sq[tot].nw=A[i]; tot++,sq[tot].kd=2,sq[tot].ps=i,sq[tot].nw=rs[i]; } sort(sq+1,sq+tot+1,cmp),tot=0; for(int i=1;i<=n*3;i++,tot++){ if(sq[i].kd==0) ls[sq[i].ps]=tot; if(sq[i].kd==1) A[sq[i].ps]=tot; if(sq[i].kd==2) rs[sq[i].ps]=tot; } for(int i=1;i<=n;i++){ update(rt[i-1],0,tot,ls[i],rs[i],i+n); ins(rt[i],rt[i-1],0,tot,A[i],i); } DINIC(),printf("%d\n",ans); return 0; }