CF1499G Graph Coloring
阿新 • • 發佈:2021-07-22
一、題目
二、解法
首先考慮定邊怎麼做,考慮構造得到最小解,我們先把所有環刪掉,然後原圖就剩下的若干條路徑,我們把度為奇數的點作為某一條路徑的端點,度為偶數的點不作為端點,那麼答案就取到了下界:\(\sum[deg[u]\%2=1]\)
題目要求動態加邊,並且強制線上,那就真的只能加邊了唄,我們討論一個新加邊的兩個節點的情況:
- 如果都不是路徑的端點,那麼可以直接把這條邊當成路徑加進去。
- 如果其中一個是路徑的端點,那麼把這條邊接到路徑上面去。
- 如果都是路徑的端點,那麼考慮把這兩條路徑連起來,考慮連在這兩個點上的兩條邊如果顏色相同,那麼直接連上去;如果顏色不同,那麼翻轉其中一條路徑的所有邊的顏色。
主要問題是維護翻轉操作,我們把邊看成點,考慮用帶權並查集來維護。眾所周知帶權並查集是可以打標記的,並查集中我們用到根路徑上的所有標記 \(rev\) 的異或和來表示這條邊的顏色。
然後每個點維護 \(sum[0/1]\) 表示藍邊和紅邊的總和,翻轉的時候可以不用交換它們而直接用 \(rev\) 作為下標。因為翻轉只會翻轉根,我們在翻轉的時候維護一下雜湊值即可,時間複雜度 \(O(n\alpha)\)
三、總結
最小化問題可以考慮構造出答案下界(\(\tt construction\ force\) 最喜歡這麼考了,我總是想不到)
有整體標記和合並問題可以考慮帶權並查集(這個權的含義實際上就是標記)
#include <cstdio> #include <iostream> using namespace std; const int M = 400005; const int MOD = 998244353; 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,q,id,hs,fa[M],a[M],rev[M],to[M],sum[M][2];//0:bule 1:red int find(int x) { if(fa[x]==x) return x; if(fa[fa[x]]==fa[x]) return fa[x]; int t=find(fa[x]); rev[x]^=rev[fa[x]]; return fa[x]=t; } void tag(int x) { x=find(x); hs=(hs-sum[x][rev[x]^1]+MOD)%MOD; rev[x]^=1; hs=(hs+sum[x][rev[x]^1])%MOD; } int col(int x) { if(x==fa[x]) return rev[x]; int t=find(x); return rev[x]^rev[t]; } void merge(int x,int y) { x=find(x);y=find(y); if(x==y) return ; sum[y][rev[y]]=(sum[y][rev[y]]+sum[x][rev[x]])%MOD; sum[y][rev[y]^1]=(sum[y][rev[y]^1]+sum[x][rev[x]^1])%MOD; fa[x]=y;rev[x]^=rev[y]; } void link(int x,int y) { id++;fa[id]=id; sum[id][0]=a[id]=(a[id-1]<<1)%MOD; //case1: a brand new path if(!to[x] && !to[y]) { to[x]=to[y]=id; return ; } //case2: have a same vertex if(!to[x]) swap(x,y); if(!to[y]) { if(!col(to[x])) tag(id); merge(to[x],id); to[x]=0;to[y]=id; return ; } //case3: have two vertex if(col(to[x])!=col(to[y])) tag(to[x]); if(!col(to[x])) tag(id); merge(to[x],id); merge(to[y],id); to[x]=to[y]=0; } signed main() { n=read();m=read();q=read(); a[0]=1; for(int i=1;i<=q;i++) { int u=read(),v=read(); link(u,v+n); } q=read(); while(q--) { int op=read(); if(op==1) { int u=read(),v=read(); link(u,v+n); printf("%d\n",hs); } else { int ans=0; for(int i=1;i<=id;i++) if(col(i)) ans++; printf("%d",ans); for(int i=1;i<=id;i++) if(col(i)) printf(" %d",i); puts(""); } fflush(stdout); } }