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 }
时间: 2024-12-20 06:57:58

UVALive - 6910 (离线逆序并查集)的相关文章

UVALive 6910 Cutting Tree(并查集应用)

总体来说,这个题给的时间比较长,样例也是比较弱的,别的方法也能做出来. 我第一次使用的是不合并路径的并查集,几乎是一种暴力,花了600多MS,感觉还是不太好的,发现AC的人很多都在300MS之内的过得. 看到他们的做法后,我知道了这个题比较好的做法. 逆向思维的并查集,因为这里只有去边操作,完全可以离线计算,把删边当成加边,然后逆序输出答案即可. 但是,这个却有一个坑,很坑,只有第一次删除的时候,我们才对他进行操作,加边的时候也只能在第一次删除的时候加.当时因为这里,十分困惑-- 这是我无路径压

Connections in Galaxy War ZOJ - 3261 离线操作+逆序并查集 并查集删边

#include<iostream> #include<cstring> #include<stdio.h> #include<map> #include<vector> #define cle(a) memset(a,0,sizeof(a)) using namespace std; const int N=50000+10; int w[20100]; bool cmp(int a,int b){ return a>b; } int n

UVALive 4730 Kingdom 线段树+并查集

题目链接:点击打开链接 题意见白书P248 思路: 先把读入的y值都扩大2倍变成整数 然后离散化一下 用线段树来维护y轴 区间上每个点的 城市数量和联通块数量, 然后用并查集维护每个联通块及联通块的最大最小y值,还要加并查集的秩来记录每个联通块的点数 然后就是模拟搞.. T^T绝杀失败题..似乎数组开小了一点就过了,== #include<stdio.h> #include<math.h> #include<vector> #include<string.h>

hdu 5441 Travel 离线带权并查集

Travel Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5441 Description Jack likes to travel around the world, but he doesn’t like to wait. Now, he is traveling in the Undirected Kingdom. There are n cities and m

hdu 5441 travel 离线+带权并查集

Time Limit: 1500/1000 MS (Java/Others)  Memory Limit: 131072/131072 K (Java/Others) Problem Description Jack likes to travel around the world, but he doesn’t like to wait. Now, he is traveling in the Undirected Kingdom. There are n cities and m bidir

UVALive - 3027 - Corporative Network (并查集!!)

UVALive - 3027 Corporative Network Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description A very big corporation is developing its corporative network. In the beginning each of the N enterprises of the cor

UVaLive 7456 Least Crucial Node (并查集+暴力)

题意:求标号最小的最大割点.(删除该点后,指定点#sink能到达的点数减少最多). 析:由于不知道要去掉哪个结点,又因为只有100个结点,所以我们考虑用一个暴力,把所有的结点都去一次,然后用并查集去判断. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #includ

UVALive 3027 Corporative Network(并查集之四)

问题描述: 求出点到根的距离,带权并查集. 代码思路: 在 I 命令的执行过程中,并不路径压缩. 当执行 E 查询命令时在路径压缩的同时递归求解存储在dist数组里面. 代码: #include<stdio.h> #include<math.h> #include<stdlib.h> #include<string.h> #define MOD 1000 #define MAX 20000 int pre[MAX+7],dist[MAX+7]; int fi

uvalive 4730王国kingdom(并查集+线段树)

 题意:有T组测试数据,每组数据的N表示有N个城市,接下来的N行里每行给出每个城市的坐标(0<=x,y<=1000000),然后有M(1<M<200000)个操作,操作有两类,(1)"road A B",表示将城市A和城市B通过一条道路连接,如果A和B原来属于不同的城市群,经过这个操作,A和B就在一个城市群里了,保证每条道路不会和其他道路相交(除了端点A和B).(2)"line C",表示查询当穿过y=C的直线,有多少个城市群.这几个城市