ZOJ-3261 Connections in Galaxy War---离线操作+逆序并查集
题目链接:
https://cn.vjudge.net/problem/ZOJ-3261
题目大意:
给你一些点,还有一些边,每个点上都有一个权值,然后有一些询问,分为两种,
query a 询问与a直接或者间接想连的点中最大权值的是那个点,输出那个点,如果那个点的权值小于等于a的权值,那么就输出-1,还有另一种操作就是destroy a b意思是删除a b的关系。
解题思路:
此处需要删边,应该想到逆序离线处理。先将所有需要删除的边直接删除,将所有操作存下来逆序处理,对于需要删的边就变成添加这条边。求与a相连的权值最大的点,就直接求a这个连通块中的最大权值的点,可以用并查集求,添加边的时候就合并两个连通块即可。
注意合并连通块时,权值大的为父亲,如果权值相同,那么编号小的为父亲
在最后判断是否存在为-1的时候,需要用连通块根节点的权值和当前询问节点权值进行比较,不可用下标相等比较
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 1e5 + 10; 5 int n, m; 6 int a[maxn];//每个点的权值 7 vector<int>Map[maxn];//存边(只保留编号小的指向编号大的边) 8 struct node//存储操作 9 { 10 int type, x, y; 11 }op[maxn]; 12 vector<int>ans; 13 int fa[maxn]; 14 int Find(int x) 15 { 16 return x == fa[x] ? x : fa[x] = Find(fa[x]); 17 } 18 void Union(int x, int y) 19 { 20 x = Find(x), y = Find(y); 21 if(a[x] < a[y]) 22 { 23 fa[x] = y; 24 } 25 else if(a[x] > a[y]) 26 { 27 fa[y] = x; 28 } 29 else if(x != y) 30 { 31 if(x < y) 32 { 33 fa[y] = x; 34 } 35 else 36 { 37 fa[x] = y; 38 } 39 } 40 } 41 int main() 42 { 43 int flag = 0; 44 while(scanf("%d", &n) != EOF) 45 { 46 if(flag++)printf("\n"); 47 memset(op, 0, sizeof(op)); 48 memset(a, 0, sizeof(a)); 49 ans.clear(); 50 for(int i = 0; i < n; i++)scanf("%d", &a[i]), Map[i].clear(), fa[i] = i; 51 52 scanf("%d", &m); 53 int u, v; 54 while(m--) 55 { 56 scanf("%d%d", &u, &v); 57 if(u > v)swap(u, v); 58 Map[u].push_back(v); 59 } 60 scanf("%d", &m); 61 char s[10]; 62 for(int i = 1; i <= m; i++) 63 { 64 scanf("%s", s); 65 if(s[0] == 'q') 66 op[i].type = 1, scanf("%d", &op[i].x); 67 else //先将边全部删除,逆序操作,逐渐增加边 68 { 69 op[i].type = 2; 70 scanf("%d%d", &u, &v); 71 if(u > v)swap(u, v); 72 op[i].x = u, op[i].y = v; 73 Map[u].erase(find(Map[u].begin(), Map[u].end(), v)); 74 } 75 } 76 for(int i = 0; i < n; i++) 77 { 78 for(int j = 0; j < Map[i].size(); j++) 79 { 80 Union(i, Map[i][j]); 81 } 82 } 83 for(int i = m; i >= 1; i--) 84 { 85 if(op[i].type == 1) 86 { 87 u = Find(op[i].x); 88 if(a[u] <= a[op[i].x])u = -1; 89 //不能仅仅判断u != op[i].x 因为根节点可能为其他点并且权值等于该节点权值,此时该节点也应该认为无连接 90 ans.push_back(u); 91 } 92 else 93 { 94 Union(op[i].x, op[i].y); 95 } 96 } 97 for(int i = ans.size() - 1; i >= 0; i--) 98 printf("%d\n", ans[i]); 99 } 100 return 0; 101 }
越努力,越幸运