[省選集訓2022] 模擬賽14
阿新 • • 發佈:2022-03-15
wait
題目描述
有一些黑白區間 \([l_i,r_i]\),有些區間已經被指定了顏色,有些區間還沒有。你需要指定未染色區間的顏色,使得對於數軸上每個點,覆蓋他的黑區間和白區間個數差的絕對值 \(\leq 1\)
\(n\leq 10^9,m\leq 3\cdot 10^4\)
解法
事實上看到這個差的絕對值 \(\leq 1\) 我的 \(\tt DNA\) 就有反應了,好像集訓隊作業中有類似的題,但是我沒有回想起來,只是差值絕對值 \(\leq 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); } }