您的位置:首页 > 其它

zoj2334 Monkey King , 并查集,可并堆,左偏树

2016-04-19 19:53 411 查看
提交地址:点击打开链接

题意: N(N<=10^5)仅仅猴子,初始每仅仅猴子为自己猴群的猴王。每仅仅猴子有一个初始的力量值。这些猴子会有M次会面。

每次两仅仅猴子x,y会面,若x,y属于同一个猴群输出-1,否则将x,y所在猴群的猴王的力量值减半,然后合并这两个猴群。

新猴群中力量值最高的为猴王。

输出新猴王的力量值。

分析:涉及集合的查询,合并,取最值。 利用并查集和左偏树就可以解决。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 200000;
int tot, v[maxn], l[maxn], r[maxn], d[maxn], f[maxn];
int findset(int x)
{return f[x]==x?x:f[x]=findset(f[x]);}
int Merge(int x, int y)
{
if(!x) return y;
if(!y) return x;
if(v[x] < v[y]) swap(x, y);  //大顶堆
r[x] = Merge(r[x], y); //递归合并右子树和Y
f[r[x]] = x;  //更新T右子树的根
if(d[l[x]] < d[r[x]]) //维护堆性质
swap(l[x], r[x]);
d[x] = d[ r[x] ] + 1;
return x;
}
int Init(int x)
{
tot++;
v[tot] = x;
f[tot] = tot;
l[tot] = r[tot] = d[tot] = 0;
}
int Insert(int x, int y)
{
return Merge(x, Init(y));
}
int Top(int x)
{
return v[x];
}
int Pop(int x)
{
int L = l[x], R = r[x];
f[L] = L;
f[R] = R;
v[x] /= 2;
r[x] = l[x] = d[x] = 0;
return Merge(L, R);
}
void solve(int x, int y)
{
int left = Pop(x), right = Pop(y);
left = Merge(left, x);
right = Merge(right, y);
left = Merge(left, right);
printf("%d\n", Top(left));
}
int main()
{
int n, m, i, x, y;
while(~scanf("%d", &n))
{
tot = 0;
for(i=1; i<=n; ++i)
{
scanf("%d",&x);
Init(x);
}
scanf("%d", &m);
for(i=1; i<=m; ++i)
{
scanf("%d%d", &x, &y);
int fx = findset(x), fy = findset(y);
if(fx==fy)
{
printf("-1\n");
}
else
{
solve(fx, fy);
}
}
}
return 0;
}
/*
5
20
16
10
10
4
5
2 3
3 4

8
5
5
-1
10
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: