[BZOJ 1455]罗马游戏(左偏树+并查集)

Description

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

Solution

比较裸的一道左偏树

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define MAXN 1000005
using namespace std;
int n,m,father[MAXN];
bool die[MAXN];
struct Node
{
    int lch,rch,w,d;
    Node():lch(0),rch(0),w(0),d(0){}
}heap[MAXN];
int merge(int x,int y)
{
    if(!x||!y)return x+y;
    if(heap[x].w>heap[y].w)swap(x,y);
    heap[x].rch=merge(y,heap[x].rch);
    if(heap[heap[x].lch].d<heap[heap[x].rch].d)swap(heap[x].lch,heap[x].rch);
    heap[x].d=heap[heap[x].rch].d+1;
    return x;
}
int find(int x)
{
    if(x==father[x])return x;
    return father[x]=find(father[x]);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&heap[i].w);
        father[i]=i;}
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        char opt[3];int x,y;
        scanf("%s",opt);
        if(opt[0]=='M')
        {
            scanf("%d%d",&x,&y);
            if(die[x]||die[y])continue;
            int fx=find(x),fy=find(y);
            if(fx!=fy)
            father[fx]=father[fy]=merge(fx,fy);
        }
        else
        {
            scanf("%d",&x);
            if(die[x])printf("0\n");
            else
            {
                int fx=find(x);
                die[fx]=1;
                printf("%d\n",heap[fx].w);
                father[fx]=merge(heap[fx].lch,heap[fx].rch);
                father[father[fx]]=father[fx];
            }
        }
    }
    return 0;
} 

 

posted @ 2017-05-24 23:35  Zars19  阅读(189)  评论(0编辑  收藏  举报