UVALive - 6910 (离线逆序并查集)

  题意:给处编号从1~n这n个节点的父节点,得到含有若干棵树的森林;然后再给出k个操作,分两种'C x'是将节点x与其父节点所连接的支剪短;'Q a b'是询问a和b是否在同一棵树中。

  题解:一开始拿到题目绞尽脑汁咋都想不到哇该怎么做在线查询,,,除了用暴力外一脸懵逼(不过确实能用暴力水过...=_=); 正解就是将其逆序离线处理: 先根据k个查询去掉所有要剪去的边后将剩余的边进行并查集处理,然后将k个查询逆序地处理查询结果;如果是剪边操作,则是将该节点与父节点并起来。  另外要注意的是,同一条边可能剪多次。

 1 /**
 2 *@author Wixson
 3 */
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <cstdio>
 7 #include <cstring>
 8 #include <cmath>
 9 #include <set>
10 #include <utility>
11 #include <vector>
12 #include <map>
13 #include <queue>
14 #include <stack>
15 const int inf=0x3f3f3f3f;
16 const double PI=acos(-1.0);
17 const double EPS=1e-10;
18 using namespace std;
19 typedef long long ll;
20 typedef pair<int,int> P;
21 
22 int n,k;
23 int a[20005],f[20005];
24 int ans[5050];
25 int book[20005];
26 typedef struct node
27 {
28     char str[5];
29     int x,y;
30 } node;
31 node q[5050];
32 void init()
33 {
34     for(int i=1; i<=n; i++) f[i]=i;
35 }
36 int find(int x)
37 {
38     if(f[x]==x) return x;
39     return f[x]=find(f[x]);
40 }
41 void unite(int x,int y)
42 {
43     int tx=find(x),ty=find(y);
44     if(tx!=ty) f[ty]=tx;
45 }
46 int main()
47 {
48     //freopen("input.txt","r",stdin);
49     int t;
50     scanf("%d",&t);
51     for(int K=1; K<=t; K++)
52     {
53         scanf("%d%d",&n,&k);
54         for(int i=1; i<=n; i++) scanf("%d",&a[i]);
55         //
56         memset(book,0,sizeof(book));
57         for(int i=1; i<=k; i++)
58         {
59             scanf("%s",q[i].str);
60             if(q[i].str[0]=='Q') scanf("%d%d",&q[i].x,&q[i].y);
61             else
62             {
63                 scanf("%d",&q[i].x);
64                 if(a[q[i].x]) book[q[i].x]++;
65             }
66         }
67         //
68         init();
69         for(int i=1; i<=n; i++)
70         {
71             if(!a[i]||book[i]) continue;
72             //
73             unite(a[i],i);
74         }
75         //
76         int cnt=1;
77         for(int i=k; i>=1; i--)
78         {
79             if(q[i].str[0]=='Q')
80             {
81                 if(find(q[i].x)==find(q[i].y)) ans[cnt++]=1;
82                 else ans[cnt++]=0;
83             }
84             else
85             {
86                 if(a[q[i].x])
87                 {
88                     book[q[i].x]--;
89                     if(!book[q[i].x]) unite(a[q[i].x],q[i].x);
90                 }
91             }
92         }
93         //
94         printf("Case #%d:\n",K);
95         for(int i=cnt-1; i>=1; i--) if(ans[i]) printf("YES\n");
96             else printf("NO\n");
97     }
98     return 0;
99 }

 

posted @ 2017-03-06 21:57  爱喝可乐的咖啡  阅读(247)  评论(0编辑  收藏  举报