题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261
题意:有很多颗星球,各自有武力值,星球间有一些联系通道,现在发生战争,有一些联系通道会被摧毁,而一些星球会通过还没有被摧毁的联系通道直接或者间接联系能够联系到的武力值最高的星球求救,如果有多个武力值都为最高的,那就联系一个编号最小的。现在给出一系列求救和摧毁的序列,一次执行,并对于每一个求救指令寻找合适的求救星球编号,如果没有可以求救的则输出 -1
这是一道启发题,有时候正这困难倒着反倒简单。
怎么说,链接好然后断开链接并不是简简单单就能实现的要么复杂度巨高要么就是不存在的。
所以还不如直接要断开的直接都不连,倒着来遇到要断开的位置再连上,这样就是简单的并查集了
#include <iostream> #include <cstring> #include <cstdio> #include <map> using namespace std; const int M = 5e4 + 10; int n , m , q , val[M] , f[M] , pos[M] , num[M] , ans[M]; struct TnT { int x , y , z; }T[M] , node[M]; bool vis[M]; map<int , int>mmp[M]; int find(int x) { if(x == f[x]) return x; return f[x] = find(f[x]); } void Union(int x , int y) { int a = find(x) , b = find(y); if(a != b) { f[a] = b; if(num[b] < num[a]) { num[b] = num[a]; pos[b] = pos[a]; } else if(num[b] == num[a]) { if(pos[a] < pos[b]) { pos[b] = pos[a]; } } } } int main() { int u , v; bool first = true; char cp[20]; while(scanf("%d" , &n) != EOF) { if(first) first = false; else printf(" "); for(int i = 0 ; i < n ; i++) { scanf("%d" , &val[i]); f[i] = i , pos[i] = i , num[i] = val[i]; mmp[i].clear(); } scanf("%d" , &m); for(int i = 1 ; i <= m ; i++) { scanf("%d%d" , &u , &v); if(u > v) { int tmp = u; u = v; v = tmp; } T[i].x = u; T[i].y = v; mmp[u][v] = i; vis[i] = false; } scanf("%d" , &q); for(int i = 1 ; i <= q ; i++) { scanf("%s" , cp); if(cp[0] == 'q') { scanf("%d" , &node[i].x); node[i].z = 1; } else { scanf("%d%d" , &u , &v); node[i].z = 2; if(u > v) { int tmp = u; u = v; v = tmp; } node[i].x = u , node[i].y = v; vis[mmp[u][v]] = true; } } for(int i = 1 ; i <= m ; i++) { if(!vis[i]) { Union(T[i].x , T[i].y); } } int cnt = 0; for(int i = q ; i >= 1 ; i--) { if(node[i].z == 1) { int g = node[i].x; int end = find(g); if(num[end] > val[g]) ans[cnt++] = pos[end]; else ans[cnt++] = -1; } else { Union(node[i].x , node[i].y); } } for(int i = cnt - 1 ; i >= 0 ; i--) { printf("%d " , ans[i]); } } return 0; }