题目大意:
给你
n
n
n个点,坐标为
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi),每个点可染成红色或者蓝色,代价分别为
R
R
R和
B
B
B。
有若干限制,每个限制使得某一行或者某一列的红色和蓝色的点数的差小于等于
d
i
d_i
di。
问最小染色代价,有解则输出解,否则输出
−
1
-1
−1。
分析:
假设某一行有
s
s
s个点(列同理),假设最小限制为
d
d
d,红色点数为
R
R
R,蓝色点数为
B
B
B,那么有
R
+
B
=
s
R+B=s
R+B=s
∣
R
−
B
∣
<
=
d
|R-B|<=d
∣R−B∣<=d
也就是
∣
2
R
−
s
∣
<
=
d
|2R-s|<=d
∣2R−s∣<=d
⌈
s
−
d
2
⌉
<
=
R
<
=
⌊
s
+
d
2
⌋
\lceil\frac{s-d}{2}\rceil<=R<=\lfloor\frac{s+d}{2}\rfloor
⌈2s−d⌉<=R<=⌊2s+d⌋
也就是说每个点的红色点有一个限制,考虑使用上下界网络流。
首先拆成两列点,第一列表示横坐标,第二列表示纵左边,一个点
(
x
,
y
)
(x,y)
(x,y)就是一条从
x
x
x到
y
y
y的流量为
1
1
1的边,当然这个要离散化,然后
S
S
S向所有左边的点连一条流量上述限制的点,右边的点向
T
T
T同理。
我们假设
(
x
,
y
)
(x,y)
(x,y)这条边有流量,则选择代价小的一个,否则选择代价大的。这样相当于跑有限制的最大流,输出方案时判断即可。
代码:
#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");
}
}
}