1. 程式人生 > >Bzoj 2733: [HNOI2012]永無鄉 數組Splay+啟發式合並

Bzoj 2733: [HNOI2012]永無鄉 數組Splay+啟發式合並

memory clas ring solved script none 通過 接下來 update

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

Bzoj 2733: [HNOI2012]永無鄉 數組Splay+啟發式合並