Bzoj 2733: [HNOI2012]永无乡 数组Splay+启发式合并

2733: [HNOI2012]永无乡

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

-1
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\n");
130             else
131             {
132                 printf("%d\n",get_rank(x,y));
133             }
134         }
135     }
136     return 0;
137 }
View Code
posted @ 2017-09-24 16:47  Hzoi_joker  阅读(200)  评论(1编辑  收藏  举报