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("
");
 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
", ans[i]);
 99     }
100     return 0;
101 }
原文地址:https://www.cnblogs.com/fzl194/p/9320665.html