其他分享
首页 > 其他分享> > Codeforces 704 D

Codeforces 704 D

作者:互联网

这题有一些前置知识:有源汇有上下界最大流

首先,如果\(r<b\),那么我们希望\(r\)更多;否则我们希望\(b\)更多。其实如果\(r<b\),那么我们可以将\(r\)看成\(1\),\(b\)看成\(0\),目标是那么我们相当于将贡献从\(r\)和\(b\)变成了\(0\)和\(1\)。

那么考虑一个有上下界的最大流:

我们对于每行、每列各建立一个节点。对于一个在第\(i\)行,第\(j\)列的点,那么我们从\(i\)连一条到\(j\)的边,并限制这条边的流量为\([0,1]\)。

那么我们得到一个类似二分图的东西,我们设\(deg(i)\)表示每个点的入度或出度。

之后我们建立source:\(S\)和sink\(T\),从\(S\)连向第\(i\)行,并且限制为\([\lceil\frac{deg(i)-d}{2}\rceil,\lfloor\frac{deg(i)+d}{2}]\rfloor\)。即我们认为行和列的差距不能超过\(d\)。

对于第\(j\)列我们则连向\(T\),限制和上面的类似,也是关于行列差即不能超过\(d\)的要求。

让\(1\)尽可能多,也就是让流量在限制内,尽可能大。

那么我们就将这题变成一个有源汇有上下界最大流的板子了。

注意这题数据比较大,Dinic要加上弧优化,自测在极限数据上可以快几百倍。

#include<bits/stdc++.h>
#define debug(...) std::cerr<<#__VA_ARGS__<<" : "<<__VA_ARGS__<<std::endl

using ll=long long;

const int maxn=200105;
const ll INF=1e18;

int S,T,s,t,n,m,r,b;

struct edge {
	int to,rev; ll cap;
};

int px[maxn],py[maxn],level[maxn],cur[maxn];
std::vector<edge> G[maxn]; 
std::vector<std::array<ll,4>> constraints;

void add(int x,int y,ll z) {	
	G[x].push_back((edge){y,(int)G[y].size(),z});
	G[y].push_back((edge){x,(int)G[x].size()-1,0});
}

bool bfs(int ss,int tt) {
	memset(level,-1,sizeof level);
	memset(cur,0,sizeof cur);
	std::queue<int> q; level[ss]=0; q.push(ss);
	while(!q.empty()) {
		int pos=q.front(); q.pop();
		for(auto nxt : G[pos])
			if(nxt.cap&&level[nxt.to]==-1) {
				level[nxt.to]=level[pos]+1;
				q.push(nxt.to);
			}
	}
	return level[tt]!=-1;
}

ll flow(int now,const int &dest,ll f) {
	if(now==dest||f<=0) return f;
	ll ret=0,rec;
	for(int i=cur[now];i<(int)G[now].size();i++,cur[now]++) {
		edge &nxt=G[now][i];
		assert(nxt.to!=now);
		if(level[now]<level[nxt.to]&&(rec=flow(nxt.to,dest,std::min(f,nxt.cap)))) {
			nxt.cap-=rec;
			G[nxt.to][nxt.rev].cap+=rec;
			ret+=rec; f-=rec;
			if(f<=0) break;
		}
	}
	return ret;
}

ll dinic(int ss,int tt) {
	ll rec=0,ret=0;
	while(bfs(ss,tt)) {
		while(rec=flow(ss,tt,INF)) {
			ret+=rec;
		}
	}
	return ret;
}

ll sz[maxn],p[maxn];
std::unordered_map<ll,std::vector<int>> index;
char path[maxn];

int main() {
	scanf("%d%d%d%d",&n,&m,&r,&b);
	std::map<int,int> rr,cc,cntx,cnty;
	std::vector<int> vx,vy;
	for(int i=1;i<=n;i++) {
		scanf("%d%d",&px[i],&py[i]);
		index[1000000000ll*(px[i]-1)+py[i]-1].push_back(i);
		vx.push_back(px[i]); cntx[px[i]]++;
		vy.push_back(py[i]); cnty[py[i]]++;
	}
	for(int i=1;i<=m;i++) {
		int x,y,z; scanf("%d%d%d",&x,&y,&z);
		if(x==1) {
			if(!rr.count(y)) rr[y]=z;
			else rr[y]=std::min(rr[y],z); 
		}
		if(x==2) {
			if(!cc.count(y)) cc[y]=z;
			else cc[y]=std::min(cc[y],z);
		}
	}
	std::sort(vx.begin(),vx.end()); vx.resize(std::unique(vx.begin(),vx.end())-vx.begin());
	std::sort(vy.begin(),vy.end()); vy.resize(std::unique(vy.begin(),vy.end())-vy.begin());
	S=(int)vx.size()+(int)vy.size()+1;
	T=(int)vx.size()+(int)vy.size()+2;
	for(int i=0;i<(int)vx.size();i++) {
		if(!rr.count(vx[i])) constraints.push_back({S,i+1,0,INF});
		else constraints.push_back({S,i+1,std::max(0,(cntx[vx[i]]-rr[vx[i]]+1)/2),(cntx[vx[i]]+rr[vx[i]])/2});
	}
	for(int i=0;i<(int)vy.size();i++) {
		if(!cc.count(vy[i])) constraints.push_back({i+(int)vx.size()+1,T,0,INF});
		else constraints.push_back({i+(int)vx.size()+1,T,std::max(0,(cnty[vy[i]]-cc[vy[i]]+1)/2),(cnty[vy[i]]+cc[vy[i]])/2});
	}
	for(int i=1;i<=n;i++) {
		int ix=std::lower_bound(vx.begin(),vx.end(),px[i])-vx.begin()+1;
		int iy=std::lower_bound(vy.begin(),vy.end(),py[i])-vy.begin()+(int)vx.size()+1;
		constraints.push_back({ix,iy,0,1});
	}
	s=(int)vx.size()+(int)vy.size()+3;
	t=(int)vx.size()+(int)vy.size()+4;
	for(auto item : constraints) {
		if(item[2]>item[3]) {
			printf("-1\n");
			exit(0);
		}
		p[item[0]]+=item[2]; p[item[1]]-=item[2];
		add(item[0],item[1],item[3]-item[2]);
	}
	for(int i=0;i<maxn;i++) sz[i]=G[i].size();
	add(T,S,INF);
	for(int i=1;i<=n+m+2;i++) {
		if(p[i]<0) add(s,i,-p[i]);
		else if(p[i]>0) add(i,t,p[i]);
	}
	dinic(s,t); ll ans=0;
	for(auto item : G[s])
		if(item.cap!=0) {
			printf("-1\n");
			exit(0);
		}
	for(auto item : G[T])
		if(item.to==S)
			ans=G[item.to][item.rev].cap;
	for(int i=0;i<maxn;i++) G[i].resize(sz[i]);
	ans+=dinic(S,T);
	printf("%lld\n",1ll*ans*std::min(r,b)+1ll*(n-ans)*std::max(r,b));	
	for(int i=1;i<=(int)vx.size();i++) {
		for(auto item : G[i]) {
			if((int)vx.size()<item.to&&item.to<=(int)vx.size()+(int)vy.size()) {
				char ch;
				if(item.cap==0) {
					if(r<b) ch='r'; else ch='b';
				} else {
					if(r>b) ch='r'; else ch='b';
				}
				ll ind=1000000000ll*(vx[i-1]-1)+vy[item.to-(int)vx.size()-1]-1;
				path[index[ind].back()]=ch; index[ind].pop_back();
			}
		}
	}
	for(int i=1;i<=n;i++) putchar(path[i]);
	return 0;
}

标签:std,nxt,level,704,ll,Codeforces,item,int
来源: https://www.cnblogs.com/Nastia/p/16471682.html