1. 程式人生 > >bzoj3706反色刷 尤拉圖+並查集(尤拉圖性質簡介)

bzoj3706反色刷 尤拉圖+並查集(尤拉圖性質簡介)

題意:一個無向圖,每條邊有黑白兩種顏色,要求用最少的反色刷使得所有邊變為白色,注意刷子會回到出發點。
明顯歐拉回路,注意到歐拉回路的性質,即無向圖任意點的點數不能使奇數。那麼我們用並查集維護每個連通塊內黑色邊的數量以及他們的度數,用桶存起來。一個基本的維護。
既然涉及到了,就順便貼一波相關吧。

判斷尤拉路是否存在的方法
有向圖:圖連通,有一個頂點出度大入度1,有一個頂點入度大出度1,其餘都是出度等於入度。

無向圖:圖連通,只有兩個頂點是奇數度,其餘都是偶數度的。

判斷歐拉回路是否存在的方法

有向圖:圖連通,所有的頂點出度等於入度。

無向圖:圖連通,所有頂點都是偶數度。
#include<cstdio>
#include<algorithm> #include<cstring> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int N=1e6+5; int n,m,cnt[3],d[N]; int f[N],size[N],ans; struct node { int x,y,z; }e[N]; inline int find(int x) { if (f[x]==x)return
x; else return f[x]=find(f[x]); } int main() { scanf("%d%d",&n,&m); fo(i,1,n)f[i]=i; fo(i,1,m) { int x,y,z; scanf("%d%d%d",&x,&y,&z); e[i].x=x,e[i].y=y,e[i].z=z; if (!z)d[x]+=2,d[y]+=2; else d[x]++,d[y]++; int
fx=find(x),fy=find(y); if (fx!=fy)f[fx]=fy; } fo(i,1,n)++cnt[d[i]%2];; fo(i,1,m) { int x=e[i].x,y=e[i].y,z=e[i].z; int fx=find(x); if (z) { if (!size[fx])++ans; ++size[fx]; } } int q; scanf("%d",&q); while (q--) { int op; scanf("%d",&op); if(op==1) { int id; scanf("%d",&id); int x=e[++id].x,y=e[id].y,z=e[id].z; int fx=find(x); if(!z) { if (!size[fx])ans++; size[fx]++; cnt[d[x]%2]--,cnt[d[y]%2]--; d[x]--,d[y]--; cnt[d[x]%2]++,cnt[d[y]%2]++; } else { --size[fx]; if (!size[fx])ans--; cnt[d[x]%2]--,cnt[d[y]%2]--; d[x]++,d[y]++; cnt[d[x]%2]++,cnt[d[y]%2]++; } e[id].z=1-z; } else { int tmp=ans; if (cnt[1])tmp=-1; printf("%d\n",tmp); } } }