zoukankan      html  css  js  c++  java
  • P3224 [HNOI2012]永无乡

    题目描述

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

    现在有两种操作:

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

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

    输入输出格式

    输入格式:

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

    接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 aibi ,表示一开始就存在一座连接岛 ai和岛 bi的桥。

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

    输出格式:

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

    输入输出样例

    输入样例#1: 
    5  1
    4  3 2 5 1
    1  2
    7
    Q 3 2
    Q 2 1
    B 2 3
    B 1 5
    Q 2 1
    Q 2 4
    Q 2 3
    输出样例#1: 
    -1
    2
    5
    1
    2

    说明

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

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

    Solution:

      本题操作看完就是一眼题,Spaly码农上线。

      初始时每个节点为一棵splay,然后对于两点的联系,由于各树高均为$log n$级别,所以直接暴力往上跳找到这两点所在的splay的根节点,若不同就启发式合并,把节点数较少的splay暴力插入到节点数多的那棵splay中。至于查询就是裸的第k大值查询了。

      时间复杂度$O(nlog n)$。

    代码:

    /*Code by 520 -- 9.20*/
    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define RE register
    #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
    #define son(x) (x==ch[fa[x]][1])
    using namespace std;
    const int N=500005;
    int n,m,Q[N],tot;
    int root[N],cnt,ch[N][2],fa[N],date[N],id[N],siz[N];
    
    int gi(){
        int a=0;char x=getchar();
        while(x<'0'||x>'9') x=getchar();
        while(x>='0'&&x<='9') a=(a<<3)+(a<<1)+(x^48),x=getchar();
        return a;
    }
    
    il int newnode(int x){date[++cnt]=x;siz[cnt]=1;return cnt;}
    
    il void pushup(int rt){siz[rt]=siz[ch[rt][0]]+siz[ch[rt][1]]+1;}
    
    il void rotate(int x){
        int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b];
        if(z) ch[z][c]=x; fa[x]=z;
        if(a) fa[a]=y; ch[y][b]=a;
        fa[y]=x,ch[x][!b]=y;
        pushup(y),pushup(x);
    }
    
    il void splay(int x,int i){
        while(fa[x]!=i) {
            int y=fa[x],z=fa[y];
            if(z==i) rotate(x),fa[x]=i;
            else {
                if(son(x)==son(y)) rotate(y),rotate(x);
                else rotate(x),rotate(x);
            }
        }
    }
    
    int getfa(int x){return !fa[x]?x:getfa(fa[x]);}
    
    void insert(int &rt,int x){
        if(!rt) {rt=x,siz[x]=1;return;}
        if(date[x]<date[rt]) insert(ch[rt][0],x),fa[ch[rt][0]]=rt;
        else insert(ch[rt][1],x),fa[ch[rt][1]]=rt;
        pushup(rt);
    }
    
    int getrank(int rt,int k){
        if(siz[rt]<k) return -1;
        if(siz[ch[rt][0]]+1==k) return rt;
        if(siz[ch[rt][0]]+1>k) return getrank(ch[rt][0],k);
        else return getrank(ch[rt][1],k-siz[ch[rt][0]]-1);
    }
    
    void dfs(int x){
        if(!x) return ;
        dfs(ch[x][0]),Q[++tot]=x,dfs(ch[x][1]);
    }
    
    il void merge(int x,int y){
        x=getfa(x),y=getfa(y),tot=0;
        if(siz[x]>=siz[y]){
            dfs(y);For(i,1,tot) insert(x,Q[i]),splay(Q[i],0),x=Q[i];
        }
        else {
            dfs(x);For(i,1,tot) insert(y,Q[i]),splay(Q[i],0),y=Q[i];
        }
    }
    
    int main(){
        n=gi(),m=gi();
        int x,y;char s[3];
        For(i,1,n) x=gi(),root[i]=newnode(x);
        while(m--){
            x=gi(),y=gi();
            merge(x,y);
        }
        m=gi();
        while(m--){
            scanf("%s",s),x=gi(),y=gi();
            if(s[0]=='Q') printf("%d
    ",getrank(getfa(x),y));
            else {
                x=getfa(x),y=getfa(y);
                if(x!=y) merge(x,y);
            }
        }
        return 0;
    }
  • 相关阅读:
    如何选出一支优秀的债券基金?
    来吧,今天说说股票型基金
    来吧,帮你认识基金
    债券基金有A、有B、还有C,到底买哪种?
    基金到底分几类
    来吧,一个指标让你选到优秀的“固收+"基金
    来吧,带你读懂债券基金
    Windows 彻底删除文件
    IntelliJ IDEA 工程、模块常用操作
    IntelliJ IDEA 创建项目(开发第一个程序)
  • 原文地址:https://www.cnblogs.com/five20/p/9688868.html
Copyright © 2011-2022 走看看