A - How Many Answers Are Wrong
题意:
已知区间[1,n],给出m组数据,即[l,r]区间内数据之和为s,求错误数据的数量。
拿到这道题,真的没思路,知道用并查集,但是关于如何定义s迟迟没有思路,就开始了搜文章学习(划水)的历程。
下面就记录一些自己的体会:
1、并查集中路径压缩的过程中如何更新关系域是关键;
2、根据数据定义一些合理的关系(如:集合中的根与集合中的元素的关系),才能对集合进行合并。这里可能会分一些情况讨论,最终应该是可以化简的。
然后放出学习的文章(感谢作者):
里面有关向量的思考和设计很巧妙
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 using namespace std; 5 const int maxn = 200020; 6 int f[maxn]; 7 int sum[maxn]; //记录当前结点到根的距离 8 int find(int x){ 9 //return x==f[x]?x:find(f[x]); 10 if(x != f[x]){ 11 int roota = f[x]; 12 f[x] = find(f[x]); 13 sum[x] += sum[roota]; 14 //x->rootb = x->roota + roota->rootb 15 } 16 return f[x]; 17 } 18 int main(){ 19 //freopen("in.txt","r",stdin); 20 int n,m; 21 while(scanf("%d%d", &n, &m) != EOF){ 22 for(int i=0; i<=n; i++){ 23 f[i] = i; 24 sum[i] = 0; 25 } 26 int ans = 0; 27 while(m--){ 28 int a, b, v; 29 scanf("%d%d%d", &a, &b, &v); 30 a--; 31 //join 32 int roota = find(a); 33 int rootb = find(b); 34 if(roota == rootb){ 35 if(sum[a]-sum[b] != v) ans++; 36 }else{ 37 f[roota] = rootb; 38 //定义大的数字是小的数字的根 39 sum[roota] = -sum[a] + sum[b] + v; 40 //变换成等式 sum[roota] + sum[a] = sum[b] + v; 41 //a->roota + roota->rootb == b->rootb + a->b 42 } 43 //join 44 } 45 printf("%d\n",ans); 46 } 47 return 0; 48 }
B - 食物链
摘出上博客中的一句话:
对于集合里的任意两个元素x,y而言,它们之间必定存在着某种联系,因为并查集中的元素均是有联系的(这点是并查集的实质),否则也不会被合并到当前集合中。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 const int maxn = 50010; 6 int f[maxn], relation[maxn]; 7 //relation[i]:i到根的偏移量 8 int sum; 9 void init(int n){ 10 for(int i=0; i<n; i++){ 11 f[i] = i; 12 relation[i] = 0; 13 } 14 sum = 0; 15 } 16 int find(int x){ 17 if(x != f[x]){ 18 int rootx = f[x]; 19 f[x] = find(rootx); 20 //路径压缩更新关系域//这是关键1 21 relation[x] = (relation[x] + relation[rootx]) % 3; 22 } 23 return f[x]; 24 } 25 void join(int x, int y, int d){ 26 int rootx = find(x); 27 int rooty = find(y); 28 if(rootx != rooty){ 29 f[rooty] = rootx; 30 relation[rooty] = (3 + d-1 + relation[x] - relation[y]) % 3; 31 //此处d-1题中给出的询问已知条件即0同类,1吃,2被吃 32 /*先用等式表达: 33 这里并非简单的加减,实质应该是关系的转移,可以用向量理解 34 r->rx + x->y = y->ry + ry->rx 35 ====>r[x] + k = r[y] + ry->rx 36 ====>ry->rx = r[x] + k - r[y] 37 k = d - 1 38 同理下面两式也得 39 */ 40 }else{ 41 if((d==1) && (relation[x] != relation[y])){ 42 sum++; 43 }else if((d==2) && ((d-1) != (relation[y] - relation[x] + 3) % 3)){ 44 sum++; 45 } 46 } 47 } 48 int main(){ 49 //freopen("in.txt","r",stdin); 50 int n, k; 51 scanf("%d%d", &n, &k); 52 init(n); 53 for(int i=0; i<k; i++){ 54 int d, x, y; 55 scanf("%d%d%d",&d, &x, &y); 56 if(x > n || y > n){ 57 sum++; 58 }else if((d==2) && (x == y)){ 59 sum++; 60 }else{ 61 join(x, y, d); 62 } 63 } 64 printf("%d\n",sum); 65 return 0; 66 }
C - A Bug's Life
题意:给定n个bugs,编号依次1、2、……n。它们之间只有雄性和雌性之分,并给定m对交配的情况,根据这m对交配的情况,判断是否有同性恋出现的情况。
Thinking:
定义relation[i]:结点i到根的距离:即相对与根节点的性别。
x,y在同一集合,他们相对根的距离即相对根的性别,而他们又同根,易得x,y的相对性别
x,y不再同一集合,思考向量得关系: y->x + x->rootx = y->rooty + rooty->rootx 其中y->x应为1。
1 #include <cstdio> 2 const int maxn = 2010; 3 int f[maxn]; 4 int relation[maxn]; 5 bool flag; 6 void init(int n){ 7 //这里n没有初始完( i < n )导致WA了半天 8 for(int i=0; i<=n; i++){ 9 f[i] = i; 10 relation[i] = 0; 11 } 12 } 13 int find(int x){ 14 if(x != f[x]){ 15 int rootx = f[x]; 16 f[x] = find(rootx); 17 relation[x] = (relation[rootx] + relation[x]) % 2; 18 } 19 return f[x]; 20 } 21 void join(int x, int y){ 22 int rootx = find(x); 23 int rooty = find(y); 24 if(rootx == rooty){ 25 if(relation[x] == relation[y]){ 26 flag = true; 27 } 28 }else{ 29 /*A了这题后在网上看到很多解法中这里对x,y进行分类, 30 即 x<y : 31 f[rooty] = rootx; 32 relation[rooty] = ((relation[x]+1) + relation[y]) % 2; 33 x>y : 34 f[rootx] = rooty; 35 relation[rootx] = ((relation[y]+1)%2 + relation[x]) % 2; 36 这里我认为应该可以不需要,因为查找过程中进行了路径压缩 37 */ 38 f[rooty] = rootx; 39 relation[rooty] = ((relation[x]+1) - relation[y]) % 2; 40 //这里+由向量y->x + x->rootx = y->rooty + rooty->rootx得应该是-,但%2好像算术上是等价的 41 //这里我个人认为是减,当然%2时加和减结果一样, 这里留待思考????? 42 } 43 } 44 int main(){ 45 //freopen("in.txt","r",stdin); 46 int T; 47 scanf("%d", &T); 48 for(int t=1; t<=T; t++){ 49 int b, inter; 50 scanf("%d%d",&b, &inter); 51 init(b); 52 flag = false; 53 for(int i=0; i<inter; i++){ 54 int x, y; 55 scanf("%d%d", &x, &y); 56 if(flag){ 57 continue; 58 }else{ 59 join(x, y); 60 } 61 } 62 printf("Scenario #%d:\n", t); 63 if(flag){ 64 printf("Suspicious bugs found!\n\n"); 65 }else{ 66 printf("No suspicious bugs found!\n\n"); 67 } 68 } 69 return 0; 70 }
D - Supermarket
并查集,不太想做了,以后补