ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces 704 D

2022-07-14 15:05:12  阅读:187  来源: 互联网

标签:std nxt level 704 ll Codeforces item int


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

首先,如果\(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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有