bzoj2733 永无乡 splay树的启发式合并
https://vjudge.net/problem/HYSBZ-2733
给一些带权点,有些点是互相连通的,
然后给出2种操作,在两点间加一条边,或者询问一个点所在的连通块内的第k小值的编号
并查集辅助+splay的启发式合并就行
由于结构简单,动态开点线段树合并也可以做
我写的是splay,由于一个奇怪的bug,我一气之下把之前的核心代码里的我自己写的splay和rotate代码全换成板子了
#include <bits/stdc++.h> #define endl '\n' #define ll long long #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define rep(ii,a,b) for(int ii=a;ii<=b;++ii) using namespace std; const int maxn=1e6+10,maxm=2e6+10; const int INF=0x3f3f3f3f; int casn,n,m,k; vector<int> pre; int find(int now) {return pre[now]==now?now:pre[now]=find(pre[now]);} vector<int> val; class splaytree{public: #define nd node[now] #define ndl node[node[now].son[0]] #define ndr node[node[now].son[1]] struct splaynode{ int son[2],fa,val,size; splaynode(){size=1,fa=son[0]=son[1]=0;} }; int cnt,root; vector<splaynode> node; inline void pushup(int now){nd.size=ndl.size+ndr.size+1;} inline void pushdown(int now){} inline int wh(int now){return node[nd.fa].son[1]==now;} void rotate(int now){ int fa=nd.fa,gf=node[fa].fa,c=wh(now); pushdown(fa);pushdown(now); if(gf) node[gf].son[wh(fa)]=now; nd.fa=gf; node[fa].son[c]=nd.son[c^1]; node[node[fa].son[c]].fa=fa;nd.son[c^1]=fa;node[fa].fa=now; pushup(fa);pushup(now); } void splay(int now,int dst=0){ for(;nd.fa!=dst;rotate(now)) if(node[nd.fa].fa!=dst)rotate(wh(now)==wh(nd.fa)?nd.fa:now); if(!dst) root=now; } void insert(int pos){ int now=root,fa=0,val=node[pos].val; while(now) fa=now,now=val<nd.val?nd.son[0]:nd.son[1]; now=pos; node[fa].son[val>node[fa].val]=now; nd.fa=fa; splay(now); } void order(int now){ int l=nd.son[0],r=nd.son[1]; nd.son[0]=nd.son[1]=nd.fa=0; nd.size=1; if(l) order(l); insert(now); if(r) order(r); } void merge(int a,int b){ if(a==b) return ; splay(a);splay(b); if(node[a].size>node[b].size) swap(a,b); pre[a]=b;root=b; order(a); } int kth(int now,int k){ splay(now);int lsize=0; while(now){ int lsum=lsize+ndl.size; if(k<=lsum) now=nd.son[0]; else if(k==lsum+1) return now; else lsize=lsum+1,now=nd.son[1]; } return -1; } splaytree(int n){ node.resize(n+7,splaynode()); rep(i,1,n) node[i].val=val[i]; node[0].size=0; root=0,cnt=0; } }; int main() { IO; int a,b; cin>>n>>m; val.resize(n+2); pre.resize(n+2); rep(i,1,n) cin>>val[i],pre[i]=i; splaytree tree(n); while(m--) { cin>>a>>b; a=find(a),b=find(b); tree.merge(a,b); } cin>>m;string s; while(m--){ cin>>s>>a>>b; if(s=="B") { a=find(a),b=find(b); tree.merge(a,b); }else{ a=find(a); cout<<tree.kth(a,b)<<endl; } } return 0; }