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