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;
}
原文地址:https://www.cnblogs.com/five20/p/9688868.html