Zoj 3261 Connections in Galaxy War (逆向并查集)
来源:互联网 发布:学术论文查重软件 编辑:程序博客网 时间:2024/06/05 15:18
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3261
题目大意:先给你N个城市的能力, 然后给你M条路,再然后又Q次询问,如果为 query,输入 x,则询问与当前城市x相连的且比当前城市能力大的城市中能力最大的城市的编号,如果有多个最大城市,输出编号最小的,否则输出-1.如果为destory,输入x,y,则切断x,y这条路。
解题思路:如果正向查找的话,当切断一条路时没办法确定他们之间的关系了,因为查找时为路径压缩;
但是我们可以把询问存起来,把切断的路径标记一下,没标记的路径进行合并,注意合并的时候把能力大的城市当做根,如果能力一样,位置小的当做根,倒着遍历,如果遇见切断路径,就把它加进路径里面,接着就是并查集了。
做题心得:看到这道题不会做, 网上百度一下, 学习一下, 其实发现这道题没有那么困难, 难度也就是一般的并查集, 加点技巧就可以了,只是没有做过这种类型 的题,想不到方法。 不过看到大牛写的代码只后还是很佩服他们, 用了好多技巧, 代码中的唯一标记方法, 以前只是听说, 没见过,第一次见;还有我感觉特牛的是大牛竟然用map标记变,很方便, 如果想不到了, 最好方法就是vector标记了, 也不是很方便 啊, 所以这道题收货还是不小的、
</pre></p><p>代码如下:</p><p><pre name="code" class="cpp">#include<stdio.h>#include<string.h>#include<algorithm>#include<map>using namespace std;const int N = 10005;const int M = 20005;const int Q = 50005;int f[N], ans[Q]; //f数组是并查集数组, ans数组存最后结果//每个城市struct node{ int Id; //编号 int power;//能力大小}p[N]; //城市的边struct link{ int x, y;}q[M];//存询问消息struct que{ char s[10]; int x; int y;}d[Q];//用map标记变map<int, bool> mp; //并查集int findset(int x) { return f[x] == x? x : f[x] = findset(f[x]);}//合并void merge(int x, int y) { int rootx = findset(x); int rooty = findset(y); if(rootx != rooty) //根据题意要求进行合并 { if(p[rootx].power > p[rooty].power) f[rooty] = rootx; else if(p[rootx].power < p[rooty].power) f[rootx] = rooty; else { if(p[rootx].Id > p[rooty].Id) f[rootx] = rooty; else f[rooty] = rootx; } }}int main(){ int n, m, t, flag = 1; while(~scanf("%d", &n)) { mp.clear(); //每次开始清空 for(int i = 0; i < n; i++) { scanf("%d", &p[i].power); p[i].Id = i; f[i] = i; } scanf("%d", &m); for(int i = 0; i < m; i++) { scanf("%d%d", &q[i].x, &q[i].y); //标记边 交换是因为边无向的(1,2)和(2,1)是同一条边 交换之后就可以使之更容易判断 if(q[i].x > q[i].y) swap(q[i].x, q[i].y); mp[q[i].x*10000+q[i].y] = false; //一个标记技巧, 使每条边的标记都是唯一的 } //保存查询结果 scanf("%d", &t); for(int i = 0; i < t; i++) { scanf("%s", d[i].s); if(d[i].s[0] == 'q') scanf("%d", &d[i].x); else { scanf("%d%d", &d[i].x, &d[i].y); if(d[i].x > d[i].y) swap(d[i].x, d[i].y); mp[d[i].x*10000+d[i].y] = true;//标记被毁坏的边 } } //把没有毁坏的边先合并起来 for(int i = 0; i < m; i++) if(!mp[q[i].x*10000+q[i].y]) merge(q[i].x, q[i].y); //逆向查找 int cnt = 0; for(int i = t-1; i >= 0; i--) if(d[i].s[0] == 'q') { int k = findset(d[i].x); if(p[k].power > p[d[i].x].power) ans[cnt++] = p[k].Id; else ans[cnt++] = -1; } else//如果边被毁坏,则毁坏之前肯定联通,就加进去 merge(d[i].x, d[i].y); if(flag) flag = 0; else printf("\n"); for(int i = cnt-1; i >= 0; i--) printf("%d\n", ans[i]); } return 0;}
0 0
- zoj 3261 Connections in Galaxy War(逆向并查集)
- ZOJ-3261-Connections in Galaxy War [逆向并查集]
- zoj Connections in Galaxy War(逆向并查集)
- Zoj 3563 Connections in Galaxy War 逆向并查集
- Zoj 3261 Connections in Galaxy War (逆向并查集)
- zoj 3261 Connections in Galaxy War(并查集+离线逆向操作)
- ZOJ 3261 Connections in Galaxy War (离线处理+逆向并查集)
- ZOJ 3261 Connections in Galaxy War(并查集)
- Connections in Galaxy War (逆向并查集)
- ZOJ 3261 Connections in Galaxy War【并查集】
- ZOJ 3261 Connections in Galaxy War (并查集)
- zoj 3261 - Connections in Galaxy War(并查集)
- ZOJ 3261 Connections in Galaxy War 并查集
- Zoj 3261 Connections in Galaxy War【逆序并查集】
- ZOJ Problem Set - 3261 Connections in Galaxy War(并查集)
- ZOJ-3261(Connections in Galaxy War)——并查集
- ZOJ 3261 Connections in Galaxy War(逆向处理)
- [并查集+路径压缩]zoj 3261:Connections in Galaxy War
- 25条提高iOS App性能的建议和技巧
- 双系统如何安全删除linux系统
- 条件数
- 解决insmod error required key not available
- Long和short的区别
- Zoj 3261 Connections in Galaxy War (逆向并查集)
- 浅谈java RMI
- GCD
- Mac python opencv 安装
- Git版本控制软件结合GitHub常用命令学习手册
- Maven —— 如何设置HTTP代理
- PMExt_Init 在哪里调用 ?
- 黑马程序员>>>JAVADOC的注释规范
- Windows下使用命令查看进程路径及其它的详细信息