左偏树

bzoj1455 罗马游戏
Description
罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个人,每个人都是一个独立的团。最近举行了一次平面几何测试,每个人都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻。他决定玩这样一个游戏。 它可以发两种命令: 1. Merger(i, j)。把i所在的团和j所在的团合并成一个团。如果i, j有一个人是死人,那么就忽略该命令。 2. Kill(i)。把i所在的团里面得分最低的人杀死。如果i这个人已经死了,这条命令就忽略。 皇帝希望他每发布一条kill命令,下面的将军就把被杀的人的分数报上来。(如果这条命令被忽略,那么就报0分)
Input
第一行一个整数n(1<=n<=1000000)。n表示士兵数,m表示总命令数。 第二行n个整数,其中第i个数表示编号为i的士兵的分数。(分数都是[0..10000]之间的整数) 第三行一个整数m(1<=m<=100000) 第3+i行描述第i条命令。命令为如下两种形式: 1. M i j 2. K i
Output
如果命令是Kill,对应的请输出被杀人的分数。(如果这个人不存在,就输出0)

#include<iostream>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
const int maxn=1000010;
int n,m;
int fa[maxn],die[maxn];
int val[maxn],lef[maxn],rig[maxn],dis[maxn];
int father(int u)
{
    while(fa[u]!=u)
    {
        fa[u]=fa[fa[u]];
        u=fa[u];
    }
    return u;
}
int merge(int x,int y)
{
    if(!x) return y;
    if(!y) return x;
    if(val[x]>val[y]) swap(x,y);
    rig[x]=merge(rig[x],y);
    fa[rig[x]]=x;//并查
    if(dis[rig[x]]>dis[lef[x]]) swap(lef[x],rig[x]);
    dis[x]=dis[rig[x]]+1;//如果x没有右孩子,则rig[x]=0,而dis[0]=-1,则dis[x]=0;
    return x;
}
int main()
{
    int u,v,fu,fv,t;
      scanf("%d",&n);
      for(int i=1;i<=n;i++)
      {
          scanf("%d",val+i);
          fa[i]=i;
          dis[i]=0;
          die[i]=0;
          lef[i]=0;
          rig[i]=0;
      }
      dis[0]=-1;
      char op[3];
      scanf("%d",&m);
      for(int i=1;i<=m;i++)
      {
          scanf("%s",op);
          if(op[0]=='M')
          {
            scanf("%d%d",&u,&v);
            if(die[u]||die[v]) continue;
            fu=father(u);
            fv=father(v);
            if(fu==fv) continue;
            t=merge(fu,fv);
            fa[t]=t;//成为根节点
          }
          else{

            scanf("%d",&v);
            if(die[v]) {
                printf("0\n");
            }
            else{
                fv=father(v);
                die[fv]=1;
                printf("%d\n",val[fv]);
                t=merge(lef[fv],rig[fv]);
                fa[t]=t;//成为根节点
            }
          }
      }
}

https://vjudge.net/problem/HDU-1512
题意:有n个猴子,一开始每个猴子只认识自己。每个猴子有一个力量值,力量值越大表示这个猴子打架越厉害。如果2个猴子不认识,他们就会找他们认识的猴子中力量最大的出来单挑,单挑不论输赢,单挑的2个猴子力量值减半,这2拨猴子就都认识了,不打不相识嘛。现在给m组询问,如果2只猴子相互认识,输出-1,否则他们各自找自己认识的最牛叉的猴子单挑,求挑完后这拨猴子力量最大值。
题解 :左偏树+并查集

#include<iostream>
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
const int maxn=100010;
int n,m;
int fa[maxn];
int val[maxn],lef[maxn],rig[maxn],dis[maxn];
int father(int u)
{
    while(fa[u]!=u)
    {
        fa[u]=fa[fa[u]];
        u=fa[u];
    }
    return u;
}
int merge(int &x,int &y)
{
    if(!x) return y;
    if(!y) return x;
    if(val[x]<val[y]) swap(x,y);
    rig[x]=merge(rig[x],y);
    fa[rig[x]]=x;//并查!
    if(dis[rig[x]]>dis[lef[x]]) swap(lef[x],rig[x]);
    dis[x]=dis[rig[x]]+1;//如果x没有右孩子,则rig[x]=0,而dis[0]=-1,则dis[x]=0;
    return x;
}
int pop(int &t)
{
    int l=lef[t],r=rig[t];
    fa[l]=l;//因为要暂时删掉根,所以左右子树先作为根
    fa[r]=r;
    lef[t]=rig[t]=dis[t]=0;
    return merge(l,r);
}
int main()
{
    int u,v,fu,fv,a,b,c;
    while(scanf("%d",&n)!=EOF){

      for(int i=1;i<=n;i++)
      {
          scanf("%d",val+i);
          fa[i]=i;
          dis[i]=0;
          lef[i]=0;
          rig[i]=0;
      }
      dis[0]=-1;
      scanf("%d",&m);
      for(int i=1;i<=m;i++)
      {
            scanf("%d%d",&u,&v);
            fu=father(u);
            fv=father(v);
            if(fu==fv)
            {
                printf("-1\n");
                continue;
            }
            val[fu]>>=1;
            val[fv]>>=1;
            a=pop(fu);
            b=pop(fv);
            c=merge(a,b);
            c=merge(fu,c);
            c=merge(fv,c);
            printf("%d\n",val[c]);
      }
    }
}

https://vjudge.net/problem/HDU-3031
题意:喜羊羊和灰太狼比较所持有的卡片的大小,每张卡片上都有一定的点数,有5种操作,如下:

  1. T K: 拿到第 k 堆所有牌
  2. C: 喜羊羊和灰太狼手中最大的牌进行比较,赢得一方可以把对方的所有牌全部取过来
  3. L: 失去手中最大的一张牌
  4. A P: 手中最大的牌点数加上P
  5. E Q: 手中最大的牌点数改为Q点
    共有R轮比赛,每轮都是双方轮流操作,灰太狼先抽,最后输出输赢即可。
#include<algorithm>
#include<string.h>
#include<cstdio>
using namespace std;
const int maxn=1000010;
int val[maxn],lef[maxn],rig[maxn],dis[maxn];
int merge(int &x,int &y)
{
    if(!x) return y;
    if(!y) return x;
    if(val[x]<val[y]) swap(x,y);
    rig[x]=merge(rig[x],y);
    if(dis[lef[x]]<dis[rig[x]]) swap(lef[x],rig[x]);
    dis[x]=dis[rig[x]]+1;
    return x;
}
int pop(int &x)
{
    int l=lef[x],r=rig[x];
    lef[x]=rig[x]=dis[x]=0;
    return merge(l,r);
}
int main()
{
    char op[5];
    int sum[2],root[2],num[110],group[110],curr,v,cas,n,m;
    int Happy, Wolffy;
    Happy = Wolffy = 0;
    scanf("%d",&cas);
    while(cas--)
    {
        memset(group,0,sizeof(group));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
            scanf("%d",num+i);
        curr=1;
        dis[0]=-1;
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=num[i];j++)
            {
                scanf("%d",&v);
                lef[curr]=rig[curr]=dis[curr]=0;
                val[curr]=v;
                group[i]=merge(group[i],curr);
                curr++;
            }
        }
        sum[0]=sum[1]=0;
        root[0]=root[1]=0;
        for(int i=0;i<n;i++)
        {
            scanf("%s",op);
            if(op[0]=='T')
            {
                scanf("%d",&v);
                root[i&1]=merge(root[i&1],group[v]);
                group[v]=0;
                sum[i&1]+=num[v];
                num[v]=0;
            }
            else if(op[0]=='C')
            {
                if(val[root[0]]>=val[root[1]])
                {
                    root[0]=merge(root[0],root[1]);
                    sum[0]+=sum[1];
                    root[1]=0;
                    sum[1]=0;
                }
                else
                {
                     root[1]=merge(root[0],root[1]);
                    sum[1]+=sum[0];
                    root[0]=0;
                    sum[0]=0;
                }
            }
             else if(op[0]=='L')
            {
                root[i&1]=pop(root[i&1]);
                sum[i&1]--;
            }
             else if(op[0]=='A')
            {
                scanf("%d",&v);
                val[root[i&1]]+=v;
            }
             else
            {
                scanf("%d",&v);
                int t=pop(root[i&1]);
                val[root[i&1]]=v;
                root[i&1]=merge(t,root[i&1]);
            }
        }
        printf("%d:%d\n",sum[0],sum[1]);
        if(sum[0]>=sum[1]) Wolffy++;
        else Happy++;
    }
    if(Wolffy>Happy) printf("Hahaha...I win!!\n");
    else printf("I will be back!!\n");
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 2.1.2 可并堆的定义 可并堆(Mergeable Heap)也是一种抽象数据类型,它除了支持优先队列的三个基本...
    Gitfan阅读 1,258评论 0 0
  • 左偏树的性质 本节点的键值key小于其左右子节点键值key(与二叉堆相同); 本节点的左子节点的距离大于等于本节点...
    胡哈哈哈阅读 2,408评论 0 0
  • 计算机二级C语言上机题库(南开版) 1.m个人的成绩存放在score数组中,请编写函数fun,它的功能是:将低于平...
    MrSunbeam阅读 6,093评论 1 42
  • 一年级语文上册生字表 生字表一(共400字) 啊(ā)爱(ài)安(ān)岸(àn)爸(bà)八(bā)巴(bā)...
    meychang阅读 2,633评论 0 6
  • 同事们都叫我九哥,我是女的。 我的客户,只相信我,背叛我的客户,在别处失败了还是回来找我。 我在单位,小可以写政策...
    九九弱水三千阅读 176评论 5 2