题目链接:
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261
题意:有n个星球编号为0—n-1;能量分别为p[i];有m句话,每句话输入a,b表示星球a和星球b可以相通的;
但是由于银河之战,破坏了一些通道
接下来有Q句话:destroy a b代表ab之间的通道被破坏;
query a代表求a可以向哪个星球求助,并输出编号,如果没有就输出-1;
各个星球只像能量值比自己大的星球求助,而且是尽量找到最大能量值的星球求助。
如果有多个能量值一样的星球可以求助,则找编号小的。
思路:
输入时记录每一条边
记录每一个操作和销毁的边。
输入结束后先用并查集加入所有没有被销毁的边
然后再逆序操作记录结果,此时遇到 destroy 则加入销毁的边 ,遇到 query 直接查找即可。
最终逆序输出结果。
不同的测试数据有空行。
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> #include<math.h> #include<map> #define N 50010 #define INF 0xfffffff using namespace std; struct node { int op,x,y;// 1代表查询,2代表破坏; } a[N],b[N]; int f[N], p[N], n, m, ans[N]; map<int,int> maps[N]; int Find(int x) { if(x != f[x]) f[x] = Find(f[x]); return f[x]; } void Union(int x, int y) { int px = Find(x); int py = Find(y); if(p[px] > p[py]) f[py] = px; else if(p[px] < p[py]) f[px] = py; else { if(px <= py) f[py] = px; else f[px] = py; } } void Init() { int i; memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); for(i=0; i<= n;i++) { maps[i].clear(); f[i] = i; p[i] = 0; } } int main() { char str[20]; int i, j, y, x, Q, flag=0; while(scanf("%d", &n)!=EOF) { Init(); for(i=0; i<n; i++) scanf("%d", &p[i]); scanf("%d", &m); for(i=0; i<m; i++) { scanf("%d%d", &x, &y); if(x > y) swap(x, y); b[i].x = x; b[i].y = y; maps[x][y] = 1;//代表x和y之间的通道存在; } scanf("%d", &Q); for(i=0; i<Q; i++) { scanf("%s", str); if(str[0] == 'q') { scanf("%d", &x); a[i].op = 1; a[i].x = x; } else { scanf("%d %d", &x, &y); if(x > y) swap(x, y); maps[x][y] = 0;//x和y之间的路没路; a[i].op = 2; a[i].x = x; a[i].y = y; } } for(i=0; i<m; i++)//把相关联的放到一起; { if(maps[b[i].x][b[i].y]==1) Union(b[i].x, b[i].y); } j=0; for(i=Q-1; i>=0; i--)//逆序处理每个操作; { if(a[i].op == 1) { int px = Find(a[i].x); if(p[px] > p[a[i].x]) ans[j++] = px; else ans[j++] = -1; } else if(a[i].op == 2) Union(a[i].x, a[i].y); } if(flag==0) flag=1; else printf("\n"); for(i=j-1; i>=0; i--) printf("%d\n", ans[i]); } return 0; }