「BZOJ3706」「FJ2014集训」反色刷
「题目描述」
给一张无向图,边有黑白两种颜色,现在你有一堆反色刷,可以从任意点开始刷,经过若干条边后回到起点。
现在要询问至少需要多少个反色刷可以使这张图所有边都变成白色。
因为某种原因,边的颜色是会改变的,于是。。
需要支持以下操作:
1 x 把第x条边反色(编号从0~m-1)
2 询问当前图中最少需要多少个反色刷
「输入格式」
第一行两个整数n m表示这张图有n个点m条边
接下来m行 每行3个整数 u v c表示一条无向边和这条边的颜色(0为白色 1为黑色)
接下来一个整数q 表示有q个操作
接下来q行为操作 描述如上
「输出格式」
对于每个询问 输出一行一个整数
表示最少需要的反色刷个数 如果没有合法方案输出-1
「样例输入」
6 6
1 2 1
2 3 1
1 3 1
4 5 1
5 6 1
4 6 1
14
2
1 0
2
1 1
1 2
2
1 3
1 4
1 5
2
1 3
1 4
1 5
2
「样例输出」
2
-1
1
0
1
「数据范围」
30% n <= 20, m <= 29 ,q <= 64
60% n <= 5000, m <= 5215 ,q <= 11308
100% n,m,q <= 1000000, c < 2,没有重边自环
来自出题人cxjyxxw_me的题解
首先猜想一个性质:如果有某个点连出的黑边度为奇数,则无解,否则必然有解。
证明:用欧拉回路去模拟,易证。
再猜想一个性质:如果有解的话,ans=图中含有黑边的联通块数。
证明:首先构造一个可行解,随便找一个有黑度的点,随便走向一个连出的黑边,一直走,直到回到这个点为止(显然一定会回到这个点)。现在考虑在同一个联通块的两个可行路径,设两个路径分别为u->blabla_u->u和v->blabla_v->v,他们的起点必然联通,设这段路径为u_v,则这两个路径可以合并为u->u_v->v->blabla_v->v->u_v->u->blabla_u->u。最后一个联通块的所有路径可以合并为一个,证毕。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<set> #define inf 1000000000 #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int Q,n,m,q,ans,cnt; int fa[1000005]; int u[1000005],v[1000005],c[1000005]; int d[1000005],sum[1000005]; int find(int x) { return x==fa[x]?x:fa[x]=find(fa[x]); } int main() { n=read();m=read(); for(int i=1;i<=n;i++)fa[i]=i; int p,q; for(int i=1;i<=m;i++) { u[i]=read(),v[i]=read(),c[i]=read(); p=find(u[i]),q=find(v[i]); if(p!=q) { fa[p]=q; if(sum[q]&&sum[p])ans--; sum[q]+=sum[p]; } if(c[i]) { sum[q]++;if(sum[q]==1)ans++; d[u[i]]++;d[v[i]]++; if(d[u[i]]&1)cnt++;else cnt--; if(d[v[i]]&1)cnt++;else cnt--; } else if(p!=q&&sum[q]&&sum[p])ans--; } Q=read(); int opt,x; for(int i=1;i<=Q;i++) { opt=read(); if(opt==1) { x=read();x++; c[x]^=1;p=find(u[x]); if(c[x]) { sum[p]++;if(sum[p]==1)ans++; d[u[x]]++;d[v[x]]++; if(d[u[x]]&1)cnt++;else cnt--; if(d[v[x]]&1)cnt++;else cnt--; } else { sum[p]--;if(sum[p]==0)ans--; d[u[x]]--;d[v[x]]--; if(d[u[x]]&1)cnt++;else cnt--; if(d[v[x]]&1)cnt++;else cnt--; } } else { if(cnt)puts("-1"); else printf("%d\n",ans); } } return 0; } |