标签:des style http color os java io strong for
2 3 3 T 1 2 T 3 2 Q 2 3 4 T 1 2 Q 1 T 1 3 Q 1
Case 1: 2 3 0 Case 2: 2 2 1 3 3 2好吧 我承认这道题很厉害,题意:T a b 代表将a所在的集合挂在b上,Q a总共询问3个信息:①a所在的集合,(这个很好办,find(a)的返回值就是答案);②a所在的集合中元素的个数,(这个也很容易,用一个size[]数组在合并的时候维护一下就可以了);③a移动的次数,这个就难办了,因为路径压缩会破坏原本的树结构,如果我设一个ttime[]数组,那么需要在路径压缩的时候维护它,比如说 T 1 2, T 1 3当1和3合并的时候,实际上是fa[2]=3;ttime[2]++;此时ttime[1]仍然等于1,所以当我们查找1时,首先会找的1的祖先是2,这时令ttime[1]+=ttime[2];即向上回溯祖先是,要将转移次数加给子孙。然后会找到2的祖先是3.感觉这算难一点的并查集吧,不过以前碰到过一个更难的,带权并查集,集合里的每个元素之间互相有关系(就像一张图,两个点之间有权值),那个题至今没做出来。#include <cstdio> #include <iostream> #include <cstring> #include <cctype> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <list> using namespace std; const int maxn=50100; const int INF=1<<25; int fa[maxn],size[maxn],ttime[maxn]; void Make_set(int n) { for(int i=1;i<=n;i++){ fa[i]=i; size[i]=1; ttime[i]=0; } } int Find(int x) { if(x!=fa[x]) { int t=fa[x]; fa[x]=Find(fa[x]); ttime[x]+=ttime[t];//维护ttime数组 return fa[x]; } return x; } void Union(int x,int y) { int fx=Find(x); int fy=Find(y); if(fx==fy) return ; fa[fx]=fy; size[fy]+=size[fx]; ttime[fx]++; } int main() { int a,b,T,n,m,cas=1;char c[5]; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); printf("Case %d:\n",cas++); Make_set(n); while(m--) { scanf("%s",c); if(c[0]=='T') { scanf("%d%d",&a,&b); Union(a,b); } else { scanf("%d",&a); int ans=Find(a); printf("%d %d %d\n",ans,size[ans],ttime[a]); } } } return 0; }
标签:des style http color os java io strong for
原文地址:http://blog.csdn.net/qq_16255321/article/details/38866085