2733: [HNOI2012]永无乡
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3955 Solved: 2112
[Submit][Status][Discuss]
Description
永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以到达岛 b,则称岛 a 和岛 b 是连 通的。现在有两种操作:B x y 表示在岛 x 与岛 y 之间修建一座新桥。Q x k 表示询问当前与岛 x连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪 座,请你输出那个岛的编号。
Input
输入文件第一行是用空格隔开的两个正整数 n 和 m,分别 表示岛的个数以及一开始存在的桥数。接下来的一行是用空格隔开的 n 个数,依次描述从岛 1 到岛 n 的重要度排名。随后的 m 行每行是用空格隔开的两个正整数 ai 和 bi,表示一开始就存 在一座连接岛 ai 和岛 bi 的桥。后面剩下的部分描述操作,该部分的第一行是一个正整数 q, 表示一共有 q 个操作,接下来的 q 行依次描述每个操作,操作的格式如上所述,以大写字母 Q 或B 开始,后面跟两个不超过 n 的正整数,字母与数字以及两个数字之间用空格隔开。 对于 20%的数据 n≤1000,q≤1000
对于 100%的数据 n≤100000,m≤n,q≤300000
Output
对于每个 Q x k 操作都要依次输出一行,其中包含一个整数,表 示所询问岛屿的编号。如果该岛屿不存在,则输出-1。
Sample Input
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
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
Sample Output
-1
2
5
1
2
2
5
1
2
这道题当时第一眼觉得像是图论tarjan题,然后看到了求排名的操作,这就不得不考虑平衡树了,由于平衡树我只会SPLAY,不会无旋TREAP所以我就只讲SPLAY的了。
这道题想到平衡树后就开始想合并操作,如果暴力合并最坏貌似是炸翻天的,一开始以为有什么神奇的打法,比如区间插入还自带平衡的黑科技之类的,结果同桌告诉我是启发式合并。所谓启发式合并就是暴力合并,只是有一个几乎所有人都想的到的剪枝,让小项去合并大项,时间自然会小不少。
所以对于每一次合并我们只是dfs一边当前的小子树,然后就暴力合并就好了,其他操作照常。
1 #pragma GCC optimze("O3") 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstdio> 5 #include<cstring> 6 #include<queue> 7 #include<algorithm> 8 #include<cmath> 9 #include<map> 10 #define N 100004 11 using namespace std; 12 int n,m,q,f[N],fa[N],size[N],ch[N][2],data[N]; 13 int find(int x) 14 { 15 if(f[x]==x)return x; 16 return f[x]=find(f[x]); 17 } 18 bool get(int x) 19 { 20 return x==ch[fa[x]][1]; 21 } 22 void update(int x) 23 { 24 if(x) 25 { 26 size[x]=1; 27 if(ch[x][0]) size[x]+=size[ch[x][0]]; 28 if(ch[x][1]) size[x]+=size[ch[x][1]]; 29 } 30 } 31 void rotate(int x) 32 { 33 int faa=fa[x],ffa=fa[fa[x]]; 34 int op=get(x); 35 ch[faa][op]=ch[x][op^1]; 36 fa[ch[faa][op]]=faa; 37 ch[x][op^1]=faa; 38 fa[faa]=x; 39 fa[x]=ffa; 40 if(ffa)ch[ffa][ch[ffa][1]==faa]=x; 41 update(faa); 42 update(x); 43 return; 44 } 45 void splay(int x) 46 { 47 for(int ff;ff=fa[x];rotate(x)) 48 { 49 if(fa[ff]) 50 rotate((get(x)==get(ff))?ff:x); 51 } 52 return; 53 } 54 int lart; 55 void insert(int x,int now,int faa) 56 { 57 58 if(now==0) 59 { 60 fa[x]=faa; 61 if(data[x]<data[faa]) ch[faa][0]=x; 62 else ch[faa][1]=x; 63 splay(x); 64 lart=x; 65 return; 66 } 67 if(data[x]<data[now])insert(x,ch[now][0],now); 68 else insert(x,ch[now][1],now); 69 } 70 void dfs(int x,int y) 71 { 72 int le=ch[x][0],ri=ch[x][1]; 73 ch[x][0]=ch[x][1]=0; 74 insert(x,y,0); 75 if(le)dfs(le,lart); 76 if(ri)dfs(ri,lart); 77 } 78 int get_rank(int x,int la) 79 { 80 if(la==size[ch[x][0]]+1) 81 return x; 82 if(la<=size[ch[x][0]]) 83 return get_rank(ch[x][0],la); 84 else 85 return get_rank(ch[x][1],la-size[ch[x][0]]-1); 86 } 87 int main() 88 { 89 scanf("%d%d",&n,&m); 90 for(int i=1;i<=n;i++) 91 { 92 scanf("%d",&data[i]); 93 f[i]=i;size[i]=1; 94 } 95 for(int i=1;i<=m;i++) 96 { 97 int x,y; 98 scanf("%d%d",&x,&y); 99 int aa=find(x),bb=find(y); 100 if(aa==bb)continue; 101 f[aa]=bb; 102 splay(x),splay(y); 103 if(size[x]>size[y]) 104 dfs(y,x); 105 else 106 dfs(x,y); 107 } 108 scanf("%d",&q); 109 char b[10]; 110 for(int i=1;i<=q;i++) 111 { 112 scanf("%s",b); 113 int x,y; 114 scanf("%d%d",&x,&y); 115 if(b[0]=='B') 116 { 117 int aa=find(x),bb=find(y); 118 if(aa==bb)continue; 119 f[aa]=bb; 120 splay(x),splay(y); 121 if(size[x]>size[y]) 122 dfs(y,x); 123 else 124 dfs(x,y); 125 } 126 else 127 { 128 splay(x); 129 if(size[x]<y)printf("-1 "); 130 else 131 { 132 printf("%d ",get_rank(x,y)); 133 } 134 } 135 } 136 return 0; 137 }