[省选集训2022] 模拟赛14
wait
题目描述
有一些黑白区间 \([l_i,r_i]\),有些区间已经被指定了颜色,有些区间还没有。你需要指定未染色区间的颜色,使得对于数轴上每个点,覆盖他的黑区间和白区间个数差的绝对值 \(\leq 1\)
\(n\leq 10^9,m\leq 3\cdot 10^4\)
解法
事实上看到这个差的绝对值 \(\leq 1\) 我的 \(\tt DNA\) 就有反应了,好像集训队作业中有类似的题,但是我没有回想起来,只是差值绝对值 \(\leq 1\) 这个问题,它可能指向欧拉回路。
可以把点按被覆盖次数分为奇覆盖和偶覆盖,首先考虑都是偶覆盖的情况。这时有一个特别强的限制:因为所有点最后差值都是 \(0\),所以我们把黑看成 \(1\),白看成 \(-1\),那么差分数组一定全为 \(0\)
对于黑区间,它对差分数组的影响是 \(s[l_i]\leftarrow +1\),\(s[r_i+1]\leftarrow -1\);对于白区间,它对差分数组的影响是 \(s[l_i]\leftarrow -1\),\(s[r_i+1]\leftarrow +1\),我们可以把差分数组看成度数,那么差分数组全为 \(0\) 就等价于多源点欧拉回路的充要条件:入度\(=\)出度。
所以黑区间可以看成 \(l_i\rightarrow r_i+1\) 的边,白区间可以看成 \(r_i+1\rightarrow l_i\) 的边,现在我们要把未染色的边定向,使得此图存在欧拉回路,那么就是一个混合图欧拉回路,可以用网络流解决。
那么存在奇覆盖怎么做呢?考虑把这些点添加一条 \(i - i+1\) 未定向的边,如果度数是 \(-1\) 这条边就会把度数调整成 \(0\),如果度数是 \(1\) 这条边就会把度数调整成 \(0\),直接跑网络流即可。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int M = 60005;
const int inf = 0x3f3f3f3f;
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,l[M],r[M],w[M],a[M],in[M],pre[M];
int S,T,tot=1,f[M],d[M],cur[M],id[M];
struct edge{int v,c,next;}e[M*10];
void add(int u,int v,int c)
{
e[++tot]=edge{v,c,f[u]},f[u]=tot;
e[++tot]=edge{u,0,f[v]},f[v]=tot;
}
int bfs()
{
queue<int> q;q.push(S);d[S]=1;
for(int i=1;i<=T;i++) d[i]=0;
while(!q.empty())
{
int u=q.front();q.pop();
if(u==T) return 1;
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(!d[v] && e[i].c>0)
{
d[v]=d[u]+1;
q.push(v);
}
}
}
return 0;
}
int dfs(int u,int ept)
{
if(u==T) return ept;
int tmp=0,flow=0;
for(int i=f[u];i;i=e[i].next)
{
int v=e[i].v;
if(d[v]==d[u]+1 && e[i].c>0)
{
tmp=dfs(v,min(ept,e[i].c));
if(!tmp) continue;
ept-=tmp;flow+=tmp;
e[i].c-=tmp;e[i^1].c+=tmp;
if(!ept) break;
}
}
return flow;
}
signed main()
{
freopen("wait.in","r",stdin);
freopen("wait.out","w",stdout);
n=read();read();
for(int i=1;i<=n;i++)
{
l[i]=read();r[i]=read();w[i]=read();
a[++m]=l[i];a[++m]=++r[i];
}
sort(a+1,a+1+m);m=unique(a+1,a+1+m)-a-1;
for(int i=1;i<=n;i++)
{
l[i]=lower_bound(a+1,a+1+m,l[i])-a;
r[i]=lower_bound(a+1,a+1+m,r[i])-a;
pre[l[i]]++;pre[r[i]]--;
if(w[i]==0)
in[l[i]]--,in[r[i]]++;
else if(w[i]==1)
in[l[i]]++,in[r[i]]--;
else
{
in[l[i]]--;in[r[i]]++;//0
add(r[i],l[i],1);id[i]=tot;
}
}
for(int i=1;i<=m;i++)
if((pre[i]+=pre[i-1])&1)
{
in[i]--;in[i+1]++;
add(i+1,i,1);
}
S=0;T=m+1;int sum=0;
for(int i=1;i<=m;i++)
{
if(in[i]%2) {puts("-1");return 0;}
if(in[i]>0) add(S,i,in[i]/2),sum+=in[i]/2;
if(in[i]<0) add(i,T,(-in[i])/2);
}
while(bfs())
{
for(int i=S;i<=T;i++) cur[i]=f[i];
sum-=dfs(S,inf);
}
if(sum) {puts("-1");return 0;}
for(int i=1;i<=n;i++)
{
if(w[i]!=-1) printf("%d ",w[i]);
else printf("%d ",e[id[i]].c?1:0);
}
}