zoukankan      html  css  js  c++  java
  • P3224 [HNOI2012]永无乡(平衡树合并)

    题目描述

    永无乡包含 nn 座岛,编号从 11 到 nn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nn 座岛排名,名次用 11 到 nn 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 aa 出发经过若干座(含 00 座)桥可以 到达岛 bb ,则称岛 aa 和岛 bb 是连通的。

    现在有两种操作:

    B x y 表示在岛 xx 与岛 yy 之间修建一座新桥。

    Q x k 表示询问当前与岛 xx 连通的所有岛中第 kk 重要的是哪座岛,即所有与岛 xx 连通的岛中重要度排名第 kk 小的岛是哪座,请你输出那个岛的编号。

    输入输出格式

    输入格式:

    第一行是用空格隔开的两个正整数 nn 和 mm ,分别表示岛的个数以及一开始存在的桥数。

    接下来的一行是用空格隔开的 nn 个数,依次描述从岛 11 到岛 nn 的重要度排名。随后的 mm 行每行是用空格隔开的两个正整数 a_iai​ 和 b_ibi​ ,表示一开始就存在一座连接岛 a_iai​ 和岛 b_ibi​ 的桥。

    后面剩下的部分描述操作,该部分的第一行是一个正整数 qq ,表示一共有 qq 个操作,接下来的 qq 行依次描述每个操作,操作的 格式如上所述,以大写字母 QQ 或 BB 开始,后面跟两个不超过 nn 的正整数,字母与数字以及两个数字之间用空格隔开。

    输出格式:

    对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 -1−1 。

    对于 20% 的数据
     n leq 1000, q leq 1000n≤1000,q≤1000

    对于 100% 的数据 n leq 100000, m leq n, q leq 300000

    n≤100000,m≤n,q≤300000

    思路平衡树合并   把两个平衡树中小的那个拆开每一个加入到大的平衡树中
     
    细节 本蒟蒻在这个地方出错了  2个平衡树用并差集合并后 其父节点既不是x也不是y也不是 find(x)也不是find(y) 是小的平衡树想大的平衡树里加的最后一个元素 那个元素是新的平衡树的 新的根节点 

    #include<iostream>
    
    #include<cstring>
    
    #include<stdio.h>
    
    using namespace std;
    
    const int maxn  = 100000+7;
    
    int f[maxn],val[maxn];
    
    void init(){for(int i=0;i<maxn;i++)f[i]=i;}
    
    int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
    
    int fa[maxn],ch[maxn][2],root,siz[maxn];
    
    int data[maxn];
    
    void pushup(int x){siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;}
    
    void pushdown(int x){}
    
    void rorate(int x){
    
        int f=fa[x],df=fa[f],kind=ch[fa[x]][1]==x;
    
        pushdown(f),pushdown(x);
    
        ch[f][kind]=ch[x][kind^1];fa[ch[f][kind]]=f;
    
        ch[x][kind^1]=f;fa[f]=x;fa[x]=df;
    
        if(df)ch[df][ch[df][1]==f]=x;
    
        pushup(f);pushup(x);
    
    }
    
    void splay(int x,int tar){
    
        for(int f;(f=fa[x])!=tar;rorate(x))
    
            if(fa[f]!=tar){
    
                if((ch[fa[f]][1]==f)==(ch[fa[x]][1]==x))
    
                  rorate(f);
    
                else  rorate(x);
    
            }
    
        if(!tar)root=x;
    
    }
    
    void insert(int x,int u)
    
    {
    
        int ff=0;
    
        while(u){ff=u;u=ch[u][val[x]>val[u]];}
    
        if(ff)ch[ff][val[x]>val[ff]]=x;
    
        fa[x]=ff;siz[x]=1;
    
        ch[x][0]=ch[x][1]=0;
    
        splay(x,0);
    
    }
    
    int temdata[maxn],cnt=0;
    
    void getall(int x){
    
        if(ch[x][0])getall(ch[x][0]);
    
        temdata[cnt++]=x;
    
        if(ch[x][1])getall(ch[x][1]);
    
    }
    
    void merge(int x,int y)
    
    {
    
        if(find(x)==find(y))return;
    
        x=find(x),y=find(y);
    
        if(siz[x]<siz[y])swap(x,y);
    
        cnt=0;getall(y);
    
        for(int i=0;i<cnt;i++)insert(temdata[i],x);
    
        f[x]=f[y]=temdata[cnt-1];
    
    }
    
    int find_k(int x,int k){
    
        if(siz[x]<k)return -1;
    
        if(siz[ch[x][0]]+1==k)return x;
    
        if(siz[ch[x][0]]>=k)return find_k(ch[x][0],k);
    
        return find_k(ch[x][1],k-siz[ch[x][0]]-1);
    
    }
    
    int main()
    
    {
    
        init();
    
        for(int i=1;i<maxn;i++)siz[i]=1;
    
        int N,M,Q,x,y;char op[3];
    
        scanf("%d%d",&N,&M);
    
        for(int i=1;i<=N;i++)scanf("%d",val+i);
    
        while(M--){
    
            scanf("%d%d",&x,&y);
    
            merge(x,y);
    
        }
    
        scanf("%d",&Q);
    
        while(Q--){
    
            scanf("%s%d%d",op,&x,&y);
    
            if(op[0]=='Q')printf("%d
    ",find_k(find(x),y));
    
            else merge(x,y);
    
        }
    
        return 0;
    
    }
    View Code
  • 相关阅读:
    js let
    go 语言
    第二十七篇、使用MVVM布局页面
    第二十六篇、因为自定item(nav)而使系统右滑返回手势失效的解决方法
    第四篇、点赞的粒子动画
    第二十五篇、抽屉效果的核心代码
    第二十四篇、iOS 10版本适配
    第二十三篇、使用NSURLSession时需要注意一个内存泄漏问题
    第十四篇、Ajax与Json
    第十三篇、jQuery Mobile
  • 原文地址:https://www.cnblogs.com/DWVictor/p/10283163.html
Copyright © 2011-2022 走看看