2733. [HNOI2012]永无乡【平衡树-splay】

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

 

tmd手残把rotate写错了……
中间将一个splay的点插入到另一个splay中忘了把插入的点clear……
什么鬼啊一个启发式合并的模板题为什么让我做成这样……
累觉不爱

 

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #define N (100000+100) 
  5 using namespace std;
  6 int n,m,p;
  7 int Root[N],num[N];
  8 int Val[N],Size[N],Father[N],Son[N][2];
  9 
 10 int Get(int x) {return Son[Father[x]][1]==x;}
 11 void Update(int x) {Size[x]=Size[Son[x][0]]+Size[Son[x][1]]+1;}
 12 void Clear(int x) {num[x]=Size[x]=Father[x]=Son[x][0]=Son[x][1]=0;}
 13 void Rotate(int x)
 14 {
 15     int wh=Get(x);
 16     int fa=Father[x],fafa=Father[fa];
 17     if (fafa) Son[fafa][Son[fafa][1]==fa]=x;
 18     Father[fa]=x; Son[fa][wh]=Son[x][wh^1];
 19     if (Son[fa][wh]) Father[Son[fa][wh]]=fa; 
 20     Father[x]=fafa; Son[x][wh^1]=fa;
 21     Update(fa); Update(x); 
 22 }
 23 
 24 void Splay(int x)
 25 {
 26     for (int fa;fa=Father[x];Rotate(x))
 27         if (Father[fa])
 28             Rotate(Get(x)==Get(fa)?fa:x);
 29     Root[num[x]]=x;
 30 }
 31 
 32 void Insert(int x,int y)//insert x to y
 33 {
 34     int now=Root[num[y]],fa=0;
 35     while (1)
 36     {
 37         fa=now,now=Son[now][Val[x]>Val[now]];
 38         if (now==0)
 39         {
 40             Father[x]=fa;
 41             Son[fa][Val[x]>Val[fa]]=x;
 42             Size[x]=1;
 43             num[x]=num[y];
 44             Update(fa);
 45             Splay(x);
 46             return;
 47         }
 48     }
 49 }
 50 
 51 void Dfs(int x,int y)
 52 {
 53     if (Son[x][0]) Dfs(Son[x][0],y);
 54     if (Son[x][1]) Dfs(Son[x][1],y);
 55     Clear(x); 
 56     Insert(x,y);
 57 }
 58 
 59 void Merge(int x,int y)
 60 {
 61     if (Size[x]>Size[y]) swap(x,y);
 62     Dfs(x,y); 
 63 }
 64 
 65 int Findx(int now,int x)
 66 {
 67     while (1)
 68         if (x<=Size[Son[now][0]])
 69             now=Son[now][0];
 70         else
 71         {
 72             x-=Size[Son[now][0]];
 73             if (x==1)
 74             {
 75                 Splay(now);
 76                 return now;
 77             }
 78             x--;
 79             now=Son[now][1];
 80         }
 81 }
 82 
 83 int main()
 84 {
 85     char opt[5];
 86     int x,y;
 87     scanf("%d%d",&n,&m);
 88     for (int i=1;i<=n;++i)
 89     {
 90         scanf("%d",&Val[i]);
 91         Root[i]=num[i]=i;
 92         Size[i]=1; 
 93     }
 94     //num表示每个点属于的树的标号,Root表示对于标号树的根 
 95     for (int i=1;i<=m;++i)
 96     {
 97         scanf("%d%d",&x,&y);
 98         if (num[x]!=num[y])
 99             Merge(Root[num[x]],Root[num[y]]);
100     }
101     scanf("%d",&p);
102     for (int i=1;i<=p;++i) 
103     {
104         scanf("%s%d%d",opt,&x,&y);
105         if (opt[0]=='Q') printf("%d\n",Size[Root[num[x]]]>=y?Findx(Root[num[x]],y):-1);
106         if (opt[0]=='B' && num[x]!=num[y]) Merge(Root[num[x]],Root[num[y]]);
107      }
108 }
posted @ 2018-03-31 07:26  Refun  阅读(155)  评论(0编辑  收藏  举报