题意:平面上有n个点,每个点必须涂成红色和蓝色中的一种,花费各为r和b(对所有的点花费都一样).m条限制,每条限制形如”y=b这条直线上两种颜色的点的数目之差的绝对值不能超过c”或” x=b这条直线上两种颜色的点的数目之差的绝对值不能超过c”,点数和限制数10^5,坐标范围10^9.
首先看到坐标范围很大先离散化,然后变成100000*100000的网格图每行每列的限制.那么转化成二分图,原先的每个点转换成边.因为每一行每一列的总点数是已知的,”两种颜色的点的数目之差”就可以转化成红色点和蓝色点的数目范围.接下来不妨把所有点都涂成红色,然后如果蓝色的点比红色的点花费小我们就尽量多涂蓝点,否则尽量少涂蓝点.为了统一问题的形式,在蓝色的点花费小于红色的时候我们就先全涂上蓝色,然后尽量少涂红点.不妨认为现在红色点花费较少,先涂上红点再尽量少涂蓝点.
那么就成了有上下界的网络流问题.对第i行我们建一个点Li,对第j列我们建一个点Ri,从源点向每个Li连一条流量上下界为这一行的蓝色点数目范围的边(在求解蓝点数目范围的时候要考虑到蓝点的数目还应当大于等于0小于等于这一行/列的点数),对每个Ri向汇点连一条流量上下界为这一列的蓝色点数目范围的边,对于坐标为第i行第j列的点,我们从Li向Rj连一条下界为0上界为1的边.跑有上下界的最小流即可.
注意一开始求的蓝点的数目范围可能是空集,这时候直接输出-1,不要再dinic跑可行流了.不知道别人的代码怎么样,反正我的代码很矬,即使有下界>上界的边也能跑出个可行流…
代码稍微长点.
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=400050,maxm=3000000; struct edge{ int to,next,w,num; }lst[maxm];int len=0,first[maxn],_first[maxn]; void addedge(int a,int b,int w,int num=0){ lst[len].num=num; lst[len].to=b;lst[len].next=first[a];lst[len].w=w;first[a]=len++; lst[len].num=num; lst[len].to=a;lst[len].next=first[b];lst[len].w=0;first[b]=len++; } int q[maxn],vis[maxn],dis[maxn],s,t,head,tail,T; bool bfs(){ head=tail=0;vis[s]=++T;dis[s]=1;q[tail++]=s; while(head!=tail){ int x=q[head++]; for(int pt=first[x];pt!=-1;pt=lst[pt].next){ if(lst[pt].w&&vis[lst[pt].to]!=T){ vis[lst[pt].to]=T;dis[lst[pt].to]=dis[x]+1;q[tail++]=lst[pt].to; } } } if(vis[t]==T)memcpy(_first,first,sizeof(first)); return vis[t]==T; } int dfs(int x,int lim){ if(x==t)return lim; int flow=0,a; for(int pt=_first[x];pt!=-1;pt=lst[pt].next){ _first[x]=pt; if(lst[pt].w&&dis[lst[pt].to]==dis[x]+1&&(a=dfs(lst[pt].to,min(lst[pt].w,lim-flow)))){ lst[pt].w-=a;lst[pt^1].w+=a;flow+=a; if(flow==lim)return flow; } } return flow; } int dinic(){ int ans=0,x; while(bfs()) while(x=dfs(s,0x7f7f7f7f))ans+=x; return ans; } void del(int x){ for(int pt=first[x];pt!=-1;pt=lst[pt].next)lst[pt].w=lst[pt^1].w=0; } int totflow[maxn]; int bound_flow(){//s-t minimum flow with lowerbound and upperbound int ss=t+1,tt=t+2; int sum=0; for(int i=s;i<=t;++i){ if(totflow[i]<0){ addedge(i,tt,-totflow[i]); }else{ sum+=totflow[i]; addedge(ss,i,totflow[i]); } } addedge(t,s,0x7f7f7f7f); int tmps=s,tmpt=t; s=ss;t=tt; if(dinic()!=sum){ printf("-1 ");return -1; }else{//return 0; int ans0=lst[len-1].w; lst[len-1].w=lst[len-2].w=0; del(ss);del(tt); s=tmpt;t=tmps;//printf("!"); return ans0-dinic(); } } void Add(int a,int b,int lo,int hi,int num=0){//printf("%d %d %d %d ",a,b,lo,hi); totflow[a]-=lo;totflow[b]+=lo; addedge(a,b,hi-lo,num); } int n,m,r,b; int x[maxn],y[maxn],typ[maxn],pos[maxn],delta[maxn]; int lbx[maxn],ubx[maxn],lby[maxn],uby[maxn]; int val[maxn],seq[maxn]; bool cmp(const int &a,const int &b){ return val[a]<val[b]; } int discrete(int x[],int _typ){ int tot=0,old=-1,cnt=0; for(int i=1;i<=n;++i){ val[++tot]=x[i]; } for(int i=1;i<=m;++i){ if(typ[i]==_typ)val[++tot]=pos[i]; } for(int i=1;i<=tot;++i)seq[i]=i; sort(seq+1,seq+tot+1,cmp); for(int i=1;i<=tot;++i){ if(val[seq[i]]!=old){ old=val[seq[i]];++cnt; } val[seq[i]]=cnt; } tot=0; for(int i=1;i<=n;++i){ x[i]=val[++tot]; } for(int i=1;i<=m;++i){ if(typ[i]==_typ)pos[i]=val[++tot]; } return cnt; } int cntx[maxn],cnty[maxn]; int res[maxn]; int main(){ memset(first,-1,sizeof(first)); scanf("%d%d",&n,&m); scanf("%d%d",&r,&b); bool reversed = false; if(r>b)swap(r,b),reversed=true; for(int i=1;i<=n;++i){ scanf("%d%d",&x[i],&y[i]); } for(int i=1;i<=m;++i){ scanf("%d%d%d",typ+i,pos+i,delta+i); } int totx=discrete(x,1),toty=discrete(y,2); //for(int i=1;i<=n;++i)printf("%d %d ",x[i],y[i]); //for(int i=1;i<=m;++i)printf("%d %d %d ",typ[i],pos[i],delta[i]); for(int i=1;i<=n;++i)cntx[x[i]]++,cnty[y[i]]++; ll ans=r*1LL*n; for(int i=1;i<=totx;++i){ lbx[i]=0;ubx[i]=cntx[i]; } for(int i=1;i<=toty;++i){ lby[i]=0;uby[i]=cnty[i]; } for(int i=1;i<=m;++i){ if(typ[i]==1){ lbx[pos[i]]=max(lbx[pos[i]],(cntx[pos[i]]-delta[i]+1)/2);ubx[pos[i]]=min(ubx[pos[i]],(cntx[pos[i]]+delta[i])/2); }else{ lby[pos[i]]=max(lby[pos[i]],(cnty[pos[i]]-delta[i]+1)/2);uby[pos[i]]=min(uby[pos[i]],(cnty[pos[i]]+delta[i])/2); } } s=0;t=totx+toty+1; bool no_solution=false; for(int i=1;i<=totx;++i){ Add(s,i,lbx[i],ubx[i]); if(lbx[i]>ubx[i])no_solution=true;//神坑 }//printf("!"); for(int i=1;i<=toty;++i){ Add(totx+i,t,lby[i],uby[i]); if(lby[i]>uby[i])no_solution=true;//神坑 }//printf("!"); for(int i=1;i<=n;++i){//printf("!"); Add(x[i],totx+y[i],0,1,i); }//printf("!"); if(no_solution){ printf("-1 ");return 0; } int flow=bound_flow(); if(flow!=-1){ printf("%lld ",ans+flow*1LL*(b-r)); for(int i=1;i<=totx;++i){ for(int pt=first[i];pt!=-1;pt=lst[pt].next){ if(lst[pt].num!=0&&lst[pt].w==0){ res[lst[pt].num]=1; } } }//printf("?"); if(reversed){ for(int i=1;i<=n;++i)printf("%c",res[i]?'r':'b'); }else{ for(int i=1;i<=n;++i)printf("%c",res[i]?'b':'r'); }printf(" "); } return 0; }