Description
数轴上有一些线段,需要将它们染成黑或白色,有些已经染好了颜色,现在求一种染色方案使得对于所有整点,覆盖它的黑色线段和白色线段数之差的绝对值不超过1
n < = 30000 n<=30000 n<=30000
Solution
我们把白色看做+1,黑色看做-1,问题变成要求每个位置的值只能是 [ − 1 , 0 , 1 ] [-1,0,1] [−1,0,1]
由于是区间加减,我们考虑差分变成两个点的加和减
因此可以将左端点和右端点+1拉出来离散化,只有这些点是有用的
一个点加,一个点减,我们将两个点之间连一条有向边,那么就意味着一个点出度+1,一个点入度+1
假定要求黑色线段和白色线段数之差要等于0,那么就是所有的点入度=出度,它存在一条欧拉回路,我们只需要想办法让所有点入度=出度即可。
这实际上就是混合图的欧拉回路问题,我们将未定向的边随机定向,新建源点汇点,源点向出度大于入度的点连容量为(出度-入度)/2,反之连向汇点,原图的边容量全为1,跑一遍最大流,一条增广路就意味着将路径上所有边反向,两个出入度不等的点调整了一下,且中间的所有点不改变,合法的条件就是新边全部满流。
如果我们随机定向的边被流过了说明这条边的方向定反了。
注意已经有方向的边要计算度数,但不能在网络中连这条边(因为不能修改)
回归原问题,我们要求绝对值不超过1,也就是说我们可以补上一些边使得它存在欧拉回路。
如果直接将度数为奇数的点拉出来连边是错误的
我们考虑这个东西-1,1,0,它差分的结果是-1,2,-1
2是偶点,它不会被连边,但它并不能构成欧拉回路。
实际上2应该向两个-1各连一条边,而不是-1之间连起来。
于是我们修改补边办法,将所有关键点拉出来不去重的排序,第 2 i − 1 2i-1 2i−1个点与第 2 i 2i 2i个点之间连一条随机定向的边,这样在保证了所有点都是偶点的情况下也满足了上面的情况(显然不可能连续两个2)。
跑一遍最大流即可。
Code
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
const int N=30005;
using namespace std;
int n,n1,m,ap[N][3],cs;
struct px
{
int x,w,p;
friend bool operator <(px x,px y)
{
return x.x<y.x;
}
}dw[N<<2];
int ans[N],pf[N<<1];
namespace flow
{
int fs[N<<1],nt[N<<3],dt[N<<3],pr[N<<3],fx[N<<3],m1,in[N<<1],out[N<<1],st,ed,d[N<<2],h[N<<2];
void link(int x,int y,int z)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
pr[m1]=z;
}
void addedge(int x,int y,int z)
{
link(x,y,z),link(y,x,0);
out[x]++,in[y]++;
fx[m1]=m1-1,fx[m1-1]=m1;
}
bool bfs()
{
memset(h,0,sizeof(h));
h[st]=1,d[1]=st;
int l=0,r=1;
while(l<r)
{
int k=d[++l];
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(pr[i]&&!h[p])
{
h[p]=h[k]+1;
d[++r]=p;
}
}
}
return (h[ed]>0);
}
int dinic(int k,int s)
{
if(k==ed) return s;
int sl=0,v;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(h[p]==h[k]+1&&pr[i])
{
if(v=dinic(p,min(s,pr[i])))
{
s-=v,sl+=v;
pr[i]-=v,pr[fx[i]]+=v;
if(!s) break;
}
}
}
if(!sl) h[k]=-1;
return sl;
}
}
using namespace flow;
int main()
{
srand(130938325);
cin>>m>>n;
fo(i,1,m)
{
scanf("%d%d%d",&ap[i][0],&ap[i][1],&ap[i][2]),ap[i][1]++;
dw[2*i-1]=(px){ap[i][0],i,0};
dw[2*i]=(px){ap[i][1],i,1};
ans[i]=ap[i][2];
}
sort(dw+1,dw+2*m+1);
fo(i,1,2*m)
{
if(i==1||dw[i].x!=dw[i-1].x)
{
n1++;
if(i%2==0)
{
if(rand()&1) addedge(n1,n1-1,1);
else addedge(n1-1,n1,1);
}
}
ap[dw[i].w][dw[i].p]=n1;
}
st=n1+1,ed=n1+2;
fo(i,1,m)
{
if(ap[i][2]<0)
{
ans[i]=rand()&1;
if(ans[i]==0) addedge(ap[i][0],ap[i][1],1);
else addedge(ap[i][1],ap[i][0],1);
pf[i]=m1-1;
}
else
{
if(ans[i]==0) out[ap[i][0]]++,in[ap[i][1]]++;
else out[ap[i][1]]++,in[ap[i][0]]++;
}
}
int s1=0;
fo(i,1,n1)
{
if(in[i]<out[i]) s1+=(out[i]-in[i])/2,addedge(st,i,(out[i]-in[i])/2);
if(in[i]>out[i]) addedge(i,ed,(in[i]-out[i])/2);
}
while(bfs()) s1-=dinic(st,1e9);
if(s1!=0)
{
printf("-1\n");
return 0;
}
fo(i,1,m)
{
if(ap[i][2]<0&&pr[pf[i]]==0) ans[i]^=1;
printf("%d ",ans[i]);
}
}