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

提交地址:点击打开链接

题意:  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
*/

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

时间: 2024-08-26 14:24:15

zoj2334 Monkey King , 并查集,可并堆,左偏树的相关文章

[BZOJ1455]罗马游戏-斜堆/左偏树-并查集(+数据生成器)

Problem 遗产 题目大意 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻.他决定玩这样一个游戏. 它可以发两种命令: 1. Merger(i, j).把i所在的团和j所在的团合并成一个团.如果i, j有一个人是死人,那么就忽略该命令. 2. Kill(i).把i所在的团里面得分最低的人杀死.如果i这个人已经死了,这条命令就忽略. 皇帝希望他每发布一条kill命令

【BZOJ 1455】 1455: 罗马游戏 (可并堆-左偏树+并查集)

1455: 罗马游戏 Description 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻.他决定玩这样一个游戏. 它可以发两种命令: 1. Merger(i, j).把i所在的团和j所在的团合并成一个团.如果i, j有一个人是死人,那么就忽略该命令. 2. Kill(i).把i所在的团里面得分最低的人杀死.如果i这个人已经死了,这条命令就忽略. 皇帝希望他每发布一

猴子大王Monkey King 左偏树+并查集维护

Description Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its own way and none of them knows each other. But monkeys can't avoid quarrelling, and it only happens between two monkeys who does not know e

zoj 2334 Monkey King/左偏树+并查集

原题链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1389 大致题意:N只相互不认识的猴子(每只猴子有一个战斗力值) 两只不认识的猴子之间发生冲突,两只猴子会分别请出它们认识的最强壮的 猴子进行决斗.决斗之后这,两群猴子都相互认识了. 决斗的那两只猴子战斗力减半...有m组询问 输入a b表示猴子a和b发生了冲突,若a,b属于同一个集合输出-1 否则输出决斗之后这群猴子(已合并)中最强的战斗力值... 具体思路:用并查

HDU 1512 并查集+左偏树

Monkey King Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3105    Accepted Submission(s): 1330 Problem Description Once in a forest, there lived N aggressive monkeys. At the beginning, they e

hdu 1512 Monkey King 左偏树

题目链接:HDU - 1512 Once in a forest, there lived N aggressive monkeys. At the beginning, they each does things in its own way and none of them knows each other. But monkeys can't avoid quarrelling, and it only happens between two monkeys who does not kn

Monkey King HDU - 1512 (左偏树)

Monkey King HDU - 1512 忽然看到左偏树,挺简单的,抄了个模板题练练 1 //左偏树 2 #include <bits/stdc++.h> 3 using namespace std; 4 const int maxn = 100010; 5 struct Node{ 6 int val, dis, l, r; 7 }p[maxn]; 8 int f[maxn]; 9 int gf(int x){ 10 return x == f[x] ? f[x] : f[x] = gf

[bzoj1455]罗马游戏_左偏树_并查集

罗马游戏 bzoj-1455 题目大意:给你n个人,2种操作,m次操作:1.将i号士兵所在的集合的最小值删除 2.合并i和j两个士兵所在的团体 注释:$1\le n\le 10^6$,$1\le m \le 10^5$. 想法:又是GXZlegend讲课,可并堆中的左偏树.了解一下: 一个具有堆性质的二叉树满足任意一个节点x中,dis[lson[x]]>=dis[rson[x]],其中,dis表示当前节点一直走右儿子的最长步数.合并是递归合并,我们通过递归处理一两个节点为根节点的左偏树的合并,显

[HDU1512]Monkey King(左偏树)

用并查集维护猴子们的关系,强壮值用左偏树维护就行了 Code #include <cstdio> #include <algorithm> #include <cstring> #define N 100010 using namespace std; int n,fa[N],m,fr[N]; //fr[x]维护猴子x所在集合在左偏树上的编号 int Find(int x){return x==fa[x]?x:fa[x]=Find(fa[x]);} namespace