【洛谷P3224】永无乡
题目
题目链接:https://www.luogu.com.cn/problem/P3224
永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 \(1\) 到 \(n\) 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 \(a\) 出发经过若干座(含 \(0\) 座)桥可以 到达岛 \(b\) ,则称岛 \(a\) 和岛 \(b\) 是连通的。
现在有两种操作:
- \(B\ x\ y\) 表示在岛 \(x\) 与岛 \(y\) 之间修建一座新桥。
- \(Q\ x\ k\) 表示询问当前与岛 \(x\) 连通的所有岛中第 \(k\) 重要的是哪座岛,即所有与岛 \(x\) 连通的岛中重要度排名第 \(k\) 小的岛是哪座,请你输出那个岛的编号。
思路
对于每一个点建立一棵权值线段树,区间\([l,r]\)维护在该点所连通的点中,有所少个排名在\([l,r]\)之间的岛。
那么就十分显然了,对于\(B\)操作就线段树合并,\(Q\)操作就权值线段树查询第\(k\)小即可。
注意如果并查集是\(x\)并到\(y\),那么线段树也要\(x\)并到\(y\)。当加入的一条边连接的两个点处于同一集合内就不用再合并了。
时间复杂度\(O(q\log n)\)。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100010;
int n,m,father[N],rt[N],rk[N];
char ch;
int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
struct Treenode
{
int lc,rc,cnt;
};
struct Tree
{
Treenode tree[N*20];
int tot;
void pushup(int x)
{
tree[x].cnt=tree[tree[x].lc].cnt+tree[tree[x].rc].cnt;
}
void update(int &x,int l,int r,int k)
{
if (!x) x=++tot;
if (l==r)
{
tree[x].cnt=1;
return;
}
int mid=(l+r)>>1;
if (k<=mid) update(tree[x].lc,l,mid,k);
else update(tree[x].rc,mid+1,r,k);
pushup(x);
}
void merge(int &x,int y)
{
if (!x || !y) x+=y;
else
{
merge(tree[x].lc,tree[y].lc);
merge(tree[x].rc,tree[y].rc);
pushup(x);
}
}
int ask(int x,int l,int r,int k)
{
if (l==r)
{
if (k==1 && tree[x].cnt==1) return rk[l];
else return -1;
}
int mid=(l+r)>>1;
if (tree[tree[x].lc].cnt>=k)
return ask(tree[x].lc,l,mid,k);
else
return ask(tree[x].rc,mid+1,r,k-tree[tree[x].lc].cnt);
}
}tree;
int main()
{
scanf("%d%d",&n,&m);
for (int i=1,x;i<=n;i++)
{
scanf("%d",&x);
tree.update(rt[i],1,n,x);
rk[x]=father[i]=i;
}
for (int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
x=find(x); y=find(y);
if (x!=y)
{
father[x]=y;
tree.merge(rt[y],rt[x]);
}
}
scanf("%d",&m);
while (m--)
{
while (ch=getchar()) if (ch=='B'||ch=='Q') break;
int x,y;
scanf("%d%d",&x,&y);
if (ch=='B')
{
x=find(x); y=find(y);
if (x!=y)
{
father[x]=y;
tree.merge(rt[y],rt[x]);
}
}
else
{
x=find(x);
printf("%d\n",tree.ask(rt[x],1,n,y));
}
}
return 0;
}