luogu P6185 [NOI Online 提高组]序列 并查集缩点 二分图
首先现在操作2,一个+1,一个-1。就好比权值可以在两点之间流动。我们发现,把操作2当作边,则一个联同的子图,内部的权值是可以随便流动的。我们就这个把这个子图看多一个点。这个我们用并查集来实现。那么这个并查集内的s[i]也对应求和。
我们把操作2,都处理完了,我们再考虑操作2。对于操作1,我们连边,注意此时的点已经缩小过。我们可以发现,如果一个联同子图,是二分图,则可以作到,两个部分在差不变的情况下,变成任意值。就是如果两个部分的s[i]的和相同,减去同样的差,变为0,则可以。如果一个联通子图,不是二分图,那么我们可以作到,总的奇偶性不变下,任意加减。就是如果总的s[i]的和为偶数,则可以变为0,则可行。
这题判断奇偶可能有负数,闲的写了个%2==1,找了2个小时.....
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 typedef long long ll; 6 ll s[210000],sum[3]; 7 int n,m,ans,T,a[210000],b[210000],fa[210000],siz[210000],qry[210000][2],col[210000]; 8 int ecnt,cnt,head[210000],nxt[420000],to[420000]; 9 void add(int x,int y) 10 { 11 nxt[++ecnt] = head[x]; 12 to[ecnt] = y; 13 head[x] = ecnt; 14 } 15 int getfa(int x) 16 { 17 if (fa[x] == x) 18 return x; 19 return fa[x] = getfa(fa[x]); 20 } 21 void merge(int x,int y) 22 { 23 int s1 = getfa(x),s2 = getfa(y); 24 if (s1 == s2) 25 return; 26 if (siz[s1] < siz[s2]) 27 { 28 fa[s1] = s2; 29 siz[s2] += siz[s1]; 30 }else 31 { 32 fa[s2] = s1; 33 siz[s1] += siz[s2]; 34 } 35 } 36 bool dfs(int x,int k) 37 { 38 col[x] = k; 39 sum[k] += s[x]; 40 bool suc = true; 41 for (int i = head[x];i;i = nxt[i]) 42 { 43 if (col[to[i]] == col[x]) 44 suc = false; 45 if (col[to[i]] == 0 && dfs(to[i],3 - k) == false) 46 suc = false; 47 } 48 return suc; 49 } 50 int main() 51 { 52 for (scanf("%d",&T);T;T--) 53 { 54 for (int i = 1;i <= ecnt;i++) 55 nxt[i] = 0; 56 cnt = ecnt = 0; 57 ans = 1; 58 scanf("%d%d",&n,&m); 59 for (int i = 1;i <= n;i++) 60 s[i] = col[i] = head[i] = 0; 61 for (int i = 1;i <= n;i++) 62 scanf("%d",&a[i]); 63 for (int i = 1;i <= n;i++) 64 scanf("%d",&b[i]); 65 for (int i = 1;i <= n;i++) 66 fa[i] = i,siz[i] = 1; 67 int topt,tx,ty; 68 for (int i = 1;i <= m;i++) 69 { 70 scanf("%d%d%d",&topt,&tx,&ty); 71 if (topt == 2) 72 merge(tx,ty); 73 else 74 { 75 qry[++cnt][0] = tx; 76 qry[cnt][1] = ty; 77 } 78 } 79 for (int i = 1;i <= n;i++) 80 s[getfa(i)] += b[i] - a[i]; 81 for (int i = 1;i <= cnt;i++) 82 { 83 add(getfa(qry[i][0]),getfa(qry[i][1])); 84 add(getfa(qry[i][1]),getfa(qry[i][0])); 85 } 86 for (int i = 1;i <= n;i++) 87 { 88 if (getfa(i) != i || col[i]) 89 continue; 90 sum[1] = sum[2] = 0; 91 bool suc = dfs(i,1); 92 if (suc && sum[1] != sum[2]) 93 { 94 ans = 0; 95 break; 96 } 97 if (!suc && ((sum[1] + sum[2]) & 1)) 98 { 99 ans = 0; 100 break; 101 } 102 } 103 printf("%s\n",ans ? "YES" : "NO"); 104 } 105 }
心之所动 且就随缘去吧