POJ1182 食物链 带权并查集

题目网址:http://poj.org/problem?id=1182

题意概述:看题目即可,不冗长。

 

  此题中,把已知逻辑关系的点放到一个集合之中,用并查集处理。并查集中带的权值是“该点与父节点之间的逻辑关系”。

  依次考察四个函数的写法,initial(初始化)没有特别之处,find时对权值的更新也很好理解,相当于是两个有向的箭头合并为一个箭头,judge没有变化,关键是merge,此时有三个有向箭头,并且其中一个箭头需要调整方向(当时没有注意到,wa吐)。

 

  抽取一下精髓,对于并查集中的权值,其意义往往是“该点与其父结点的关系”,并且往往需要有某种“传递性”或者叫做“累加性”。

 

  再丢出另外一个习题,同样是带权并查集。剧透:权值的意义是“该点下面的方块比父结点下面的方块多几个”。

  题目网址:http://poj.org/problem?id=1988

 

给出两个题的代码:

T1:

 1 #include
 2 #include
 3 #include
 4 #include
 5 #include
 6 #include
 7 using namespace std;
 8 
 9 int N,K;
10 struct union_find{
11     static const int maxn=50005;
12     int pa[maxn],stk[maxn],top,sta[maxn];//sta表示点i在并查集中与其父亲的关系,0同类,1吃父亲,2被父亲吃
13     void initial(int n){ for(int i=1;i<=n;i++) pa[i]=i,sta[i]=0; }
14     int f(int x,int y){ return (x+y)%3; }//关系转换函数 
15     int find(int x){
16         while(x!=pa[x]) stk[++top]=x,x=pa[x];
17         int last=0;
18         while(top){
19             int y=stk[top--];
20             sta[y]=f(last,sta[y]),last=sta[y];
21             pa[y]=x;
22         }
23         return x;
24     }
25     bool judge(int x,int y){ return find(x)==find(y); }
26     int G(int x){ find(x); return sta[x]; }//求得x与代表元之间的关系
27     int F(int x){ return (3-G(x))%3; }//对x于代表元之间的关系取反,用于调整向量的方向
28     void merge(int x,int y,int s){
29         int t1=F(x),t2=G(y);
30         x=find(x),y=find(y);
31         pa[x]=y,sta[x]=f(t1,f(s,t2));//注意合并的时候是处理了3个向量,pa[x]->x,x->y,y->pa[y]
32     }
33 }uf;
34 
35 int main()
36 {
37     scanf("%d%d",&N,&K);
38     uf.initial(N);
39     int D,X,Y,ans=0;
40     for(int i=1;i<=K;i++){
41         scanf("%d%d%d",&D,&X,&Y);
42         if(X>N||Y>N||X==Y&&D==2) ans++;
43         else if(D==1){
44             if(uf.judge(X,Y)){ if(uf.G(X)!=uf.G(Y)) ans++; }
45             else uf.merge(X,Y,0);
46         }
47         else if(D==2){
48             if(uf.judge(X,Y)){
49                 if(uf.f(uf.F(Y),uf.G(X))!=1) ans++;
50             }
51             else uf.merge(X,Y,1);
52         }
53     }
54     printf("%d\n",ans);
55     return 0;
56 }
View Code

 

T2:

 1 #include
 2 #include
 3 #include
 4 #include
 5 #include
 6 #include
 7 using namespace std;
 8 
 9 int P;
10 struct union_find{
11     static const int maxn=30005;
12     int pa[maxn],stk[maxn],top,add[maxn],sz[maxn];
13     void initial(int n){
14         for(int i=1;i<=n;i++) pa[i]=i,sz[i]=1,add[i]=0;
15     }
16     int find(int x){
17         while(x!=pa[x]) stk[++top]=x,x=pa[x];
18         int sum=add[x];
19         while(top){
20             int y=stk[top--];
21             add[y]+=sum,sum=add[y];
22             pa[y]=x;
23         }
24         return x;
25     }
26     bool judge(int x,int y){ return find(x)==find(y); }
27     void merge(int x,int y){
28         x=find(x),y=find(y);
29         add[x]+=sz[y],sz[y]+=sz[x],sz[x]=0;
30         pa[x]=y;
31     }
32     int COUNT(int x){ find(x); return add[x]; }
33 }uf;
34 
35 void read(char &ch){
36     ch=getchar();
37     while(ch!='M'&&ch!='C') ch=getchar();
38 }
39 int main()
40 {
41     uf.initial(30000);
42     scanf("%d",&P);
43     char op; int x,y;
44     for(int i=1;i<=P;i++){
45         read(op);
46         if(op=='M'){
47             scanf("%d%d",&x,&y);
48             uf.merge(x,y);
49         }
50         else if(op=='C'){
51             scanf("%d",&x);
52             printf("%d\n",uf.COUNT(x));
53         }
54     }
55     return 0;
56 }
View Code

 

你可能感兴趣的:(POJ1182 食物链 带权并查集)