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;
    }
    
    
  • 相关阅读:
    windows下命令行
    利用border画三角形
    正则
    flex布局
    css笔记
    W3C标准
    SEO相关
    左边固定,右边自适应(解决方案)
    容错性测试的测试点
    Charles安装及使用教程
  • 原文地址:https://www.cnblogs.com/NeosKnight/p/10826509.html
Copyright © 2011-2022 走看看