永無鄉[Splay啟發式合併]
阿新 • • 發佈:2018-12-15
題目描述
永無鄉包含 nn 座島,編號從 1 到 n ,每座島都有自己的獨一無二的重要度,按照重要度可以將這 n 座島排名,名次用 1 到 n 來表示。某些島之間由巨大的橋連線,通過橋可以從一個島到達另一個島。如果從島 a 出發經過若干座(含0 座)橋可以 到達島 b ,則稱島 a 和島 b 是連通的。
現在有兩種操作:
B x y 表示在島 x 與島 y 之間修建一座新橋。
Q x k 表示詢問當前與島 x 連通的所有島中第 k 重要的是哪座島,即所有與島 x 連通的島中重要度排名第 k 小的島是哪座,請你輸出那個島的編號。
輸入格式:
第一行是用空格隔開的兩個正整數 n 和 m ,分別表示島的個數以及一開始存在的橋數。
接下來的一行是用空格隔開的 n 個數,依次描述從島 1 到島 n 的重要度排名。隨後的 m 行每行是用空格隔開的兩個正整數 ai 和 bi ,表示一開始就存在一座連線島ai 和島bi 的橋。
後面剩下的部分描述操作,該部分的第一行是一個正整數 q,表示一共有 q 個操作,接下來的 q 行依次描述每個操作,操作的 格式如上所述,以大寫字母 Q 或 B 開始,後面跟兩個不超過 n 的正整數,字母與數字以及兩個數字之間用空格隔開。
輸出格式:
對於每個 Q x k 操作都要依次輸出一行,其中包含一個整數,表示所詢問島嶼的編號。如果該島嶼不存在,則輸出 -1 。
輸入樣例#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
對於 100% 的資料 n≤100000,m≤n,q≤300000
合併Splay+區間第k大
對於合併,我們把size小的一個點一個點拆開,然後插入到另一個裡面
聽起來很暴力,其實複雜度是正確的
因為小的那個大小至少翻倍,所以一個元素最多查logn次
總的複雜度為O(nlongn^2)
#include<bits/stdc++.h> #define N 100005 #define lc t[x].ch[0] #define rc t[x].ch[1] using namespace std; struct Node{ int ch[2],fa,size; }t[N]; int n,m,q,rt[N],f[N],a[N],ans,tot; char ch[20]; int read(){ int cnt=0,f=1;char ch=0; while(!isdigit(ch)){ch=getchar();if(ch=='-')f=-1;} while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar(); return cnt*f; } int find(int x){return x==f[x]?x:f[x]=find(f[x]);} void Pushup(int x){ t[x].size=t[lc].size+t[rc].size+1; } void rotate(int x,int &goal){ int y=t[x].fa,z=t[y].fa; int k=(t[y].ch[1]==x); if(y==goal) goal=x; t[z].ch[t[z].ch[1]==y]=x; t[x].fa=z; t[y].ch[k]=t[x].ch[k^1]; t[t[x].ch[k^1]].fa=y; t[x].ch[k^1]=y; t[y].fa=x; Pushup(y),Pushup(x); } void splay(int x,int &goal){ while(t[x].fa!=goal){ int y=t[x].fa,z=t[y].fa; if(z!=goal) (t[y].ch[1]==x)^(t[z].ch[1]==y)?rotate(x,goal):rotate(y,goal); rotate(x,goal); } } void insert(int u,int &x,int fa){ if(x==0){x=u;t[u].fa=fa;return;} t[x].size++; if(a[u]<=a[x]) insert(u,lc,x); else insert(u,rc,x); } void merge(int x,int y){ if(x==y) return; if(t[rt[x]].size>t[rt[y]].size) swap(x,y); f[x]=y; queue<int> q; q.push(rt[x]); while(!q.empty()){ int u=q.front(); q.pop(); if(t[u].ch[0]) q.push(t[u].ch[0]); if(t[u].ch[1]) q.push(t[u].ch[1]); insert(u,rt[y],0); splay(u,rt[y]); } } int Kth(int x,int k){ if(t[lc].size>=k) return Kth(lc,k); else if(t[lc].size==k-1) return x; return Kth(rc,k-t[lc].size-1); } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) f[i]=i,rt[i]=i,t[i].size=1; for(int i=1;i<=m;i++){ int x=read(),y=read(); merge(find(x),find(y)); } q=read(); while(q--){ scanf("%s",ch); int x=read(),y=read(); if(ch[0]=='Q'){ x=rt[find(x)]; if(t[x].size<y) printf("-1\n"); else printf("%d\n",Kth(x,y)); } if(ch[0]=='B') merge(find(x),find(y)); } }