洛谷P2713 罗马游戏
sloj bzoj1455. 罗马游戏
题目描述
罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个士兵,每个士兵都是一个独立的团。最近举行了一次平面几何测试,每个士兵都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的士兵嗤之以鼻。
他决定玩这样一个游戏。 它可以发两种命令:
M i j把i所在的团和j所在的团合并成一个团。如果i,j有一个士兵是死人,那么就忽略该命令。K i把i所在的团里面得分最低的士兵杀死。如果i这个士兵已经死了,这条命令就忽略。
皇帝希望他每发布一条 K i 命令,下面的将军就把被杀的士兵的分数报上来 (如果这条命令被忽略,那么就报0分)。
保证士兵的分数互不相同。
输入格式
第一行一个整数n,表示士兵数。
第二行n个整数a1,a2,…an,其中ai 表示编号为i的士兵的分数。
第三行一个整数m。
第3+i行描述第i条命令。命令为如下两种形式:M i j 或 K i。
输出格式
如果命令是 K i,对应的请输出被杀士兵的分数(如果这个人不存在,就输出0)。
输入输出样例
输入 #1
5 100 90 66 99 10 7 M 1 5 K 1 K 1 M 2 3 M 3 4 K 5 K 4
输出 #1
10 100 0 66
说明/提示
1≤n≤106,1≤m≤105,0≤ai≤107, 注意测试数据中 M i j 的i,j可能在同一个团中。
很明显,对于M指令来说,我们应该使用并查集来维护
然后对于K嘛……好吧,我也不是很清楚
不过有一点是明确的,那就是我们应该用堆(优先队列)来维护
再结合第一个的合并操作,这时就会想到用可并堆,也就是左偏树来维护
有了这个思路以后再来看,这不就是模板题嘛,完事
上代码
#include<bits/stdc++.h> using namespace std; int n,m,a[1000010],fa[1000010],root[1000010],ch[1000010][2],dis[1000010]; bool dead[1000010]; int find_(int x){ return fa[x]==x?x:fa[x] = find_(fa[x]); } int merge(int x,int y){ if(!x||!y) return x+y; if(a[x]>a[y]) swap(x,y); ch[x][1] = merge(ch[x][1],y); if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]); dis[x] = dis[ch[x][1]]+1; return x; } int main(){ scanf("%d",&n); for(int i = 1;i<=n;i++){ scanf("%d",&a[i]); fa[i] = i; root[i] = i; } scanf("%d",&m); for(int i = 1;i<=m;i++){ char c;int x,y; cin>>c; if(c=='M'){ scanf("%d%d",&x,&y); if(dead[x]||dead[y]) continue; x = find_(x),y = find_(y); if(x==y) continue; fa[x] = y; root[y] = merge(root[x],root[y]); }else{ scanf("%d",&x); if(dead[x]){ puts("0"); continue; } x = find_(x); printf("%d\n",a[root[x]]); dead[root[x]] = true; root[x] = merge(ch[root[x]][0],ch[root[x]][1]); } } return 0; }
梦与现实间挣扎着,所求为何
你可以借走我的文章,但你借不走我的智慧 虽然我是傻逼本文来自博客园,作者:cztq,转载请注明原文链接:https://www.cnblogs.com/cztq/p/17001719.html

浙公网安备 33010602011771号