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

猜你喜欢

转载自www.cnblogs.com/OYJason/p/9489275.html