CF704D Captain America 上下界網路流
阿新 • • 發佈:2018-12-10
題目大意:
給你個點,座標為,每個點可染成紅色或者藍色,代價分別為和。
有若干限制,每個限制使得某一行或者某一列的紅色和藍色的點數的差小於等於。
問最小染色代價,有解則輸出解,否則輸出。
分析:
假設某一行有個點(列同理),假設最小限制為,紅色點數為,藍色點數為,那麼有
也就是
也就是說每個點的紅色點有一個限制,考慮使用上下界網路流。
首先拆成兩列點,第一列表示橫座標,第二列表示縱左邊,一個點就是一條從到的流量為的邊,當然這個要離散化,然後向所有左邊的點連一條流量上述限制的點,右邊的點向同理。
我們假設這條邊有流量,則選擇代價小的一個,否則選擇代價大的。這樣相當於跑有限制的最大流,輸出方案時判斷即可。
程式碼:
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <queue> #define LL long long const int maxn=1e5+7; const int maxe=3e6+7; const LL inf=1e17; using namespace std; LL n,m,R,B,s,t,op,l,d,ns,nt,cnt; LL x[maxn],y[maxn],sx[maxn],sy[maxn],mn[maxn*2],mx[maxn*2],num[maxn],deg[maxn*2]; LL ls[maxn*2],dis[maxn*2]; queue <LL> q; struct edge{ LL y,w,op,next; }g[maxe]; struct rec{ LL x,y; }a[maxn]; void add(LL x,LL y,LL w) { g[++cnt]=(edge){y,w,cnt+1,ls[x]}; ls[x]=cnt; g[++cnt]=(edge){x,0,cnt-1,ls[y]}; ls[y]=cnt; } bool bfs() { while (!q.empty()) q.pop(); for (LL i=0;i<=nt;i++) dis[i]=inf; dis[ns]=0; q.push(ns); while (!q.empty()) { LL x=q.front(); q.pop(); for (LL i=ls[x];i>0;i=g[i].next) { LL y=g[i].y; if ((g[i].w) && (dis[y]>dis[x]+1)) { dis[y]=dis[x]+1; if (y==nt) return 1; q.push(y); } } } return 0; } LL dfs(LL x,LL maxf) { if ((x==nt) || (maxf==0)) return maxf; LL ret=0; for (LL i=ls[x];i>0;i=g[i].next) { LL y=g[i].y; if ((dis[y]==dis[x]+1) && (g[i].w)) { LL f=dfs(y,min(maxf-ret,g[i].w)); if (!f) dis[y]=0; ret+=f; g[i].w-=f; g[g[i].op].w+=f; if (ret==maxf) break; } } return ret; } LL dinic() { LL flow=0; while (bfs()) flow+=dfs(ns,inf); return flow; } int main() { scanf("%lld%lld",&n,&m); scanf("%lld%lld",&R,&B); for (LL i=1;i<=n;i++) { scanf("%lld%lld",&a[i].x,&a[i].y); x[i]=a[i].x; y[i]=a[i].y; } sort(x+1,x+n+1); sort(y+1,y+n+1); LL size1=unique(x+1,x+n+1)-x-1,size2=unique(y+1,y+n+1)-y-1; s=0,t=size1+size2+1; for (LL i=1;i<=n;i++) { LL xx=lower_bound(x+1,x+size1+1,a[i].x)-x; LL yy=lower_bound(y+1,y+size2+1,a[i].y)-y; add(xx,yy+size1,1); sx[xx]++,sy[yy]++,num[i]=cnt-1; } for (LL i=1;i<=size1+size2;i++) mn[i]=0,mx[i]=n; for (LL i=1;i<=m;i++) { scanf("%lld%lld%lld",&op,&l,&d); if (op==1) { LL p=lower_bound(x+1,x+size1+1,l)-x; if ((x[p]!=l) || (d>=sx[p])) continue; LL L=(sx[p]-d+1)/2,R=sx[p]-L; if (L>R) { printf("-1"); return 0; } mx[p]=min(mx[p],R); mn[p]=max(mn[p],L); } else { LL p=lower_bound(y+1,y+size2+1,l)-y; if ((y[p]!=l) || (d>=sy[p])) continue; LL L=(sy[p]-d+1)/2,R=sy[p]-L; if (L>R) { printf("-1"); return 0; } mx[p+size1]=min(mx[p+size1],R); mn[p+size1]=max(mn[p+size1],L); } } for (LL i=1;i<=size1;i++) { deg[s]-=mn[i]; deg[i]+=mn[i]; add(s,i,min(sx[i],mx[i])-mn[i]); } for (LL i=size1+1;i<=size1+size2;i++) { deg[i]-=mn[i]; deg[t]+=mn[i]; add(i,t,min(sy[i-size1],mx[i])-mn[i]); } LL nowcnt=cnt,S=t+1,T=t+2; add(t,s,inf); LL sum=0; for (LL i=s;i<=t;i++) { if (deg[i]<0) add(i,T,-deg[i]); else if (deg[i]>0) add(S,i,deg[i]),sum+=deg[i]; } ns=S,nt=T; if (dinic()!=sum) { printf("-1"); return 0; } for (LL i=nowcnt+1;i<=cnt;i++) g[i].w=0; ns=s,nt=t; dinic(); LL ans=0; for (int i=1;i<=n;i++) { if (!g[num[i]].w) ans+=min(B,R); else ans+=max(B,R); } printf("%lld\n",ans); for (LL i=1;i<=n;i++) { if (!g[num[i]].w) { if (B<R) printf("b"); else printf("r"); } else { if (B<R) printf("r"); else printf("b"); } } }