zoukankan      html  css  js  c++  java
  • 【UOJ#77】A+B Problem

    传送门

    题目描述

    Sol

    看到选择黑白收益不同,然后还可能有代价。
    我们想到用网络流解决,并且这应该是用总可能收益-最小割得到答案。

    考虑初步建图,发现那个限制可以直接 (n^2) 解决。
    我一开始是拆了点的,但是这样没有必要,而且可能会出现一个格子黑白两种颜色都不选的情况。

    所以就是黑色边从源点连出,然后白色边连到汇点。这样割掉哪条边代表不选这个颜色。

    因为对于一个奇怪的格子代价只算一次,所以我们新建一个点代表这个格子变成了一个奇怪的格子。
    那么对于编号小于 i 的有限制的点直接从新建点连过去一个 INF 边就行了。

    这样边数显然是 (O(n^2)),时间不去,空间也不够。
    发现连边是相当于对前缀排序后的一段区间连边,那么用主席树优化一下连边就可以了。这样点数和边数都到达 (O(nlogn)) 级别。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define Set(a,b) memset(a,b,sizeof(a))
    template<class T>inline void init(T&x){
    	x=0;char ch=getchar();bool t=0;
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    	if(t) x=-x;return;
    }typedef long long ll;
    const int N=1e5+200;
    const int MAXN=5020;
    const int M=2e6;
    const int INF=2e9;
    int n;
    struct edge{int to,next,cap;}a[M];
    int head[N],cnt=0;
    int A[MAXN],B[MAXN],W[MAXN],L[MAXN],R[MAXN],P[MAXN];
    int S,T;int ans=0;
    inline void add(int x,int y,int z){a[cnt]=(edge){y,head[x],z};head[x]=cnt++;}
    inline void add_edge(int x,int y,int z){add(x,y,z),add(y,x,0);}
    int d[N],cur[N];
    int stk[MAXN<<2],top=0;
    queue<int> Q;
    int dfs(int u,int flow){
    	if(u==T) return flow;
    	int rest=flow;
    	for(int v,&i=cur[u];~i;i=a[i].next) {
    		v=a[i].to;if(!a[i].cap||d[v]!=d[u]+1) continue;
    		int f=dfs(v,min(rest,a[i].cap));
    		if(!f) d[v]=0;
    		rest-=f,a[i].cap-=f,a[i^1].cap+=f;
    		if(!rest) break;
    	}return flow-rest;
    }
    inline bool bfs(){
    	while(!Q.empty()) Q.pop();Set(d,0);
    	d[S]=1;Q.push(S);
    	while(!Q.empty()) {
    		int u=Q.front();Q.pop();
    		for(int v,i=head[u];~i;i=a[i].next) {
    			v=a[i].to;if(!a[i].cap||d[v]) continue;
    			d[v]=d[u]+1;if(v==T) return 1;Q.push(v);
    		}
    	}return d[T];
    }
    int TAIL;
    inline int Dinic(){int flow=0;while(bfs()) memcpy(cur,head,(TAIL+1)*4),flow+=dfs(S,INF);return flow;}
    inline int ID(int x){return lower_bound(stk+1,stk+1+top,x)-stk;}
    namespace Tree{
    	int cnt=0;int rt[MAXN];int ls[N],rs[N];
    	void LINK(int u,int l,int r,int i){
    		if(!u) return;
    		if(l>=L[i]&&r<=R[i]) return add_edge(i+n,T+u,INF);
    		int mid=(l+r)>>1;
    		if(mid>=L[i]) LINK(ls[u],l,mid,i);
    		if(mid< R[i]) LINK(rs[u],mid+1,r,i);
    		return;
    	}
    	void Insert(int&u,int l,int r,int i){
    		int v=++cnt;ls[v]=ls[u],rs[v]=rs[u];
    		if(l==r) {
    			add_edge(T+v,i,INF);
    			if(u) add_edge(T+v,T+u,INF);
    			u=v;return;
    		}u=v;
    		int mid=(l+r)>>1;
    		if(mid>=A[i]) Insert(ls[u],l,mid,i);
    		else          Insert(rs[u],mid+1,r,i);
    		if(ls[u]) add_edge(T+u,T+ls[u],INF);
    		if(rs[u]) add_edge(T+u,T+rs[u],INF);
    	}
    }using Tree::rt;
    
    
    
    
    int main()
    {
    	freopen("data.in","r",stdin);
    	init(n);Set(head,-1);
    	int ans=0;
    	for(int i=1;i<=n;++i) init(A[i]),init(B[i]),init(W[i]),init(L[i]),init(R[i]),init(P[i]),ans+=B[i]+W[i],stk[++top]=A[i],stk[++top]=L[i],stk[++top]=R[i];
    	sort(stk+1,stk+1+top);top=unique(stk+1,stk+1+top)-stk-1;
    	for(int i=1;i<=n;++i) A[i]=ID(A[i]),L[i]=ID(L[i]),R[i]=ID(R[i]);
    	S=0;T=(n<<1)+1;
    	for(int i=1;i<=n;++i) {add_edge(S,i,B[i]),add_edge(i,T,W[i]),add_edge(i,i+n,P[i]);}
    	for(int i=1;i<=n;++i) {
    		rt[i]=rt[i-1];
    		if(i!=1) Tree::LINK(rt[i-1],1,top,i);
    		Tree::Insert(rt[i],1,top,i);
    	}
    	TAIL=Tree::cnt+T;
    	printf("%d
    ",ans-Dinic());
    	return 0;
    }
    
    
  • 相关阅读:
    hdu 5646 DZY Loves Partition
    bzoj 1001 狼抓兔子 平面图最小割
    poj 1815 Friendship 最小割 拆点 输出字典序
    spoj 1693 Coconuts 最小割 二者取其一式
    hdu 5643 King's Game 约瑟夫环变形
    约瑟夫环问题
    hdu 5642 King's Order
    CodeForces 631C Report
    1039: C语言程序设计教程(第三版)课后习题9.4
    1043: C语言程序设计教程(第三版)课后习题10.1
  • 原文地址:https://www.cnblogs.com/NeosKnight/p/10826509.html
Copyright © 2011-2022 走看看