永无乡[HNOI2012]
题目描述
永无乡包含 n 座岛,编号从 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 。
平衡树启发式合并
最重要的是这个东西
rt[i]表示以i为根的集合的平衡树的根
可以预估,每个点最多会合并log N次
不过可以回收节点,减免空间
inline void dfs(int u,int y) { if(ls)dfs(ls,y); if(rs)dfs(rs,y); insert(val[u],y,u); } inline void merge(int x,int y) { if(size[rt[x]]>size[rt[y]])x^=y^=x^=y;
//将小的合并到大的 f[x]=y;
dfs(rt[x],y); }
并查集维护连通性
完整代码
#include<bits/stdc++.h> #define re return #define ll long long #define ls ch[u][0] #define rs ch[u][1] #define R register #define inc(i,l,r) for(int i=l;i<=r;++i) const int maxn=100005,inf=2147483647; using namespace std; template<typename T>inline void rd(T&x) { char c;bool f=0; while((c=getchar())<'0'||c>'9')if(c=='-')f=1; x=c^48; while((c=getchar())>='0'&&c<='9')x=x*10+(c^48); if(f)x=-x; } int n,m,q,tot; int ch[maxn][2],val[maxn],size[maxn],fa[maxn],rt[maxn]; int f[maxn],import[maxn]; inline void pushup(int u){size[u]=size[ls]+size[rs]+1;} inline bool chk(int x){re ch[fa[x]][1]==x;} inline void rotate(int x) { int y=fa[x],z=fa[y],f=chk(x),w=ch[x][f^1]; ch[z][chk(y)]=x; fa[x]=z; ch[y][f]=w;fa[w]=y; ch[x][f^1]=y; fa[y]=x; pushup(y),pushup(x); } inline void splay(int x,int goal=0) { while(fa[x]!=goal) { int y=fa[x],z=fa[y]; if(z!=goal) chk(y)==chk(x)?rotate(y):rotate(x); rotate(x); } } inline void insert(int x,int goal,int ytot=0) { int u=rt[goal],p=0; while(u)p=u,u=ch[u][x>val[u]]; if(!ytot)u=++tot; else u=ytot; if(p)ch[p][x>val[p]]=u; size[u]=1; val[u]=x; fa[u]=p; ls=rs=0; splay(u); rt[goal]=u; } inline int kth(int k,int goal) { if(k>size[rt[goal]])re -1; int u=rt[goal]; while(2333) { if(size[ls]+1<k)k=k-size[ls]-1,u=rs; else if(size[ls]<k)re u; else u=ls; } } inline void dfs(int u,int y) { if(ls)dfs(ls,y); if(rs)dfs(rs,y); insert(val[u],y,u); } inline void merge(int x,int y) { if(size[rt[x]]>size[rt[y]])x^=y^=x^=y; f[x]=y; dfs(rt[x],y); } inline int find(int x) { re x==f[x]?x:f[x]=find(f[x]); } int main() { // freopen("in.txt","r",stdin); int x,y; rd(n),rd(m); inc(i,1,n) { rd(import[i]); f[i]=i; } inc(i,1,m) { rd(x),rd(y); int f1=find(x),f2=find(y); if(f1==f2)continue; else f[f1]=f2; } inc(i,1,n) insert(import[i],find(i)); char opt[2]; rd(q); while(q--) { scanf("%s",opt); rd(x),rd(y); if(opt[0]=='B') { int f1=find(x),f2=find(y); if(f1!=f2)merge(f1,f2); } else { int f1=find(x); f1=kth(y,f1); if(f1==-1)printf("-1\n"); else printf("%d\n",f1); } } re 0; }

浙公网安备 33010602011771号