• [bzoj3218] a+b problem [最小割+数据结构优化建图]


    题面

    传送门

    思路

    最小割

    我们首先忽略掉那个奇♂怪的限制,就有一个比较显然的最小割模型:

    建立源点$S$和汇点$T$

    对于每个元素$i$建立一个点$i$,连边$<S,i,w[i]>$和$<i,T,b[i]>$

    这样,割掉$<S,i>$边就表示选白色,割掉$<i,T>$边就表示选黑色,那么答案就是$sum_{i=1}^nb[i]+w[i] - mincut$

    但是现在有一个奇♂怪的限制出来了

    奇♂怪的限制

    这个限制,是当$i$点黑色,$j<i$点白色时出现的

    那么我们考虑把这个限制对答案的影响,也用最小割的方式表现出来

    我们发现,如果对于某一个点$i$,它对应的割边(就是在上面那种方法里面)是$<i,T>$,也就是它取白色的话,这个限制不会被触发

    那么我们就考虑这个点的割边是$<S,i>$的情况,此时我们发现,如果我们想把这个$p[i]$也变成最小割的一部分的话,我们就要对于所有可能触发的$j$,构成一条这样的链:

    $<S,i>-<i,j>-<j,T>$

    但是这个中间这条,显然不能直接在$i,j$中间连边,因为这样无法体现出链的特性

    我们考虑这样的一个方法,来分开黑白割的情况

    我们对于每个点,新建节点$ii$,然后对于每个$ii$,连边$<ii,i,p[i]>$

    对于$i$所有能够访问到的点,连边$<i,jj,inf>$,$inf$表示不可割

    这样跑最小割,还是用所有的$b,w$的和来减,就是答案了

    建图优化

    显然这个东西直接连边的话,$n^2$的会炸

    所以我们用一个主席树来优化一下建图

    用所有的$i$连向对应的主席树链上的所有点,主席树上的点就横向连边(旧的往新的连),然后每个点从它覆盖的所有区间连过来

    开的主席树的数组下标意义就是$a$的大小,这样方便取区间

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cassert>
    #include<cmath>
    #define ll long long
    using namespace std;
    inline int read(){
    	int re=0,flag=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){
    		if(ch=='-') flag=-1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    	return re*flag;
    }
    int n,first[200010],cnte=-1,dep[200010],cur[200010];
    struct edge{
    	int to,next;ll w;
    }a[1500010];
    void add(int u,int v,ll w){
    	a[++cnte]=(edge){v,first[u],w};first[u]=cnte;
    	a[++cnte]=(edge){u,first[v],0};first[v]=cnte; 
    }
    bool bfs(int s,int t){
    	int i,u,v,q[200010],head=0,tail=1;
    	for(i=s;i<=t;i++) dep[i]=-1,cur[i]=first[i];
    	dep[s]=0;q[0]=s;
    	while(head<tail){
    		u=q[head++];
    		for(i=first[u];~i;i=a[i].next){
    			v=a[i].to;if(~dep[v]||!a[i].w) continue;
    			dep[v]=dep[u]+1;q[tail++]=v;
    		}
    	}
    	return ~dep[t];
    }
    int dfs(int u,int t,ll lim){
    	if(u==t||!lim) return lim;
    	int i,v,f,flow=0;
    	for(i=cur[u];~i;i=a[i].next){
    		v=a[i].to;cur[u]=i;
    		if(dep[v]==dep[u]+1&&(f=dfs(v,t,min(a[i].w,lim)))){
    			flow+=f;lim-=f;
    			a[i].w-=f;a[i^1].w+=f;
    			if(!lim) return flow;
    		}
    	}
    	if(lim) dep[u]=-1;
    	return flow;
    }
    ll dinic(int s,int t){
    	ll re=0;
    	while(bfs(s,t)) re+=dfs(s,t,1e12);
    	return re;
    }
    struct chairmantree{
    	int ch[1000010][2],cnt,root[5010];
    	int insert(int l,int r,int pos,int pre,int u){
    		int cur=++cnt;
    		ch[cur][0]=ch[pre][0];ch[cur][1]=ch[pre][1];
    		add(u,cur,1e12);
    		if(l==r){
    			if(pre) add(pre,cur,1e12);
    			return cur;
    		} 
    		int mid=(l+r)>>1;
    		if(mid>=pos){
    			ch[cur][0]=insert(l,mid,pos,ch[pre][0],u);
    			if(pre) add(pre,cur,1e12);
    		}
    		else{
    			ch[cur][1]=insert(mid+1,r,pos,ch[pre][1],u);
    			if(pre) add(pre,cur,1e12); 
    		}
    		return cur;
    	}
    	void check(int l,int r,int ql,int qr,int cur,int u){
    		if(!cur) return;
    		int mid=(l+r)>>1;
    		if(l>=ql&&r<=qr){
    			add(cur,u,1e12);
    			return;
    		}
    		if(mid>=ql) check(l,mid,ql,qr,ch[cur][0],u);
    		if(mid<qr) check(mid+1,r,ql,qr,ch[cur][1],u);  
    	}
    }T;
    int main(){
    	memset(first,-1,sizeof(first));
    	n=read();int i,val,b,w,l,r,p;ll sum=0;
    	int s=0,t=200000;T.cnt=n<<1;
    	for(i=1;i<=n;i++){
    		val=read();b=read();w=read();l=read();r=read();p=read();
    		sum+=(ll)b+w;
    		add(s,i,w);add(i,t,b);add(i+n,i,p);
    		T.root[i]=T.insert(0,1e9,val,T.root[i-1],i);
    		T.check(0,1e9,l,r,T.root[i-1],i+n);
    	}
    	printf("%lld
    ",sum-dinic(s,t));
    }
    
  • 相关阅读:
    LeetCode 4 :Majority Element
    LeetCode 3 :Min Stack
    Oracle操作4
    plsql安装教程
    java Date与String互相转化
    Oracle操作3
    Oracle操作2
    Oracle操作
    Oracle11g修改密码
    Visual Studio2013完全卸载
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9451944.html
Copyright © 2020-2023  润新知