1. 程式人生 > 其它 >[省選集訓2022] 模擬賽14

[省選集訓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);
	}
}