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 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 -11 。

 

输入输出样例

输入样例#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 \leq 1000, q \leq 1000n1000,q1000

对于 100% 的数据 n \leq 100000, m \leq n, q \leq 300000n100000,mn,q300000

 

题解

这道题要求我们执行两个操作。1.判断是否在同一个集合 2.查找联通快第k小值

操作一我们可以用并查集维护,操作二的话,我们可以用splay维护

但合并怎么做呢?我看了看题解,发现有个叫做启发式合并的神器玩意儿

简而言之,就是合并两个splay时,把节点数较少的splay中每一个点都取出来插入另一个splay中(好暴力啊……暴力mo不可取……)

时间复杂度是O(n log n)的

原因?能用就好要什么原因

具体的实现请看代码

  1 //minamoto
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<cstring>
  6 #define N 500050
  7 using namespace std;
  8 inline int read(){
  9     char ch;bool flag=0;int res;
 10     while(!isdigit(ch=getchar()))
 11         (ch=='-')&&(flag=true);
 12     for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0');
 13     (flag)&&(res=-res);
 14     return res;
 15 }
 16 int n,m;
 17 struct node{
 18     int val,father,size,ch[2];
 19 } e[N];
 20 int cnt,root[N],f[N],h[N];
 21 int ff(int x){
 22     return f[x]==x?x:f[x]=ff(f[x]);
 23 }
 24 void pushup(int x){
 25     e[x].size=e[e[x].ch[0]].size+e[e[x].ch[1]].size+1;
 26 }
 27 int identify(int x){
 28     return e[e[x].father].ch[1]==x;
 29 }
 30 void connect(int x,int f,int son){
 31     e[x].father=f,e[f].ch[son]=x;
 32 }
 33 void rotate(int x){
 34     int y=e[x].father,z=e[y].father;
 35     int yson=identify(x),zson=identify(y);
 36     int b=e[x].ch[yson^1];
 37     connect(b,y,yson),connect(y,x,yson^1),connect(x,z,zson);
 38     pushup(y),pushup(x);
 39 }
 40 void splay(int x,int goal){
 41     while(e[x].father!=goal){
 42         int y=e[x].father,z=e[y].father;
 43         if(z!=goal)
 44         (identify(x)^identify(y))?rotate(x):rotate(y);
 45         rotate(x);
 46     }
 47     if(goal<=n) root[goal]=x;
 48 }
 49 void push(int x,int k){
 50     int u=root[k],fa=k;
 51     while(u&&e[u].val!=x)
 52         fa=u,u=e[u].ch[x>e[u].val];
 53     u=++cnt;
 54     e[u].size=1,e[u].father=fa;
 55     if(fa>n)
 56         e[fa].ch[x>e[fa].val]=u;
 57     e[u].val=x,e[u].ch[0]=e[u].ch[1]=0;
 58     splay(u,k);    
 59 }
 60 void dfs(int u,int k){
 61     if(e[u].ch[0]) dfs(e[u].ch[0],k);
 62     if(e[u].ch[1]) dfs(e[u].ch[1],k);
 63     push(e[u].val,k);
 64 }
 65 void merge(int a,int b){
 66     int x=ff(a),y=ff(b);
 67     if(x==y) return;
 68     if(e[root[x]].size>e[root[y]].size) swap(x,y);
 69     f[x]=y;
 70     dfs(root[x],y);
 71 }
 72 int get(int x,int k){
 73     int now=root[k];
 74     if(e[now].size<x) return -1;
 75     while(true){
 76         if(e[e[now].ch[0]].size>=x) now=e[now].ch[0];
 77         else if(e[e[now].ch[0]].size+1==x) return e[now].val;
 78         else x-=e[e[now].ch[0]].size+1,now=e[now].ch[1];
 79     }
 80 }
 81 int main(){
 82     //freopen("testdata.in","r",stdin);
 83     n=read(),m=read();
 84     for(int i=1;i<=n;++i) root[i]=i+n,f[i]=i;
 85     cnt=n+n;
 86     for(int i=1;i<=n;++i){
 87         int x=read();
 88         h[x]=i;
 89         e[i+n].val=x,e[i+n].size=1,e[i+n].father=i;    
 90     }
 91     for(int i=1;i<=m;++i){
 92         int x=read(),y=read();
 93         merge(x,y);
 94     }
 95     int t=read();
 96     while(t--){
 97         char s[5];int a,b;
 98         scanf("%s",s);a=read(),b=read();
 99         if(s[0]=='B') merge(a,b);
100         else{
101             int ans=get(b,ff(a));
102             printf("%d\n",~ans?h[ans]:ans);
103         }
104     }
105     return 0;
106 }

 

posted @ 2018-07-18 18:39  bztMinamoto  阅读(194)  评论(0编辑  收藏  举报
Live2D