【HNOI2012】永无乡 题解(并查集+线段树合并)

题目链接

给定一张含$n$个点$m$条边的无向图,每个点有一个重要指数$a_i$。有两种操作:1.在$x$和$y$之间连一条边;2.求$x$所在连通块中重要程度第$k$小的点。

---------------------------------

维护第$k$小,很容易想到权值线段树。看到合并二字,可以想到用线段树合并的方法。维护连通块可以用并查集做。

注意并查集合并的方向和线段树合并的方向要一致。查询的时候要先找出并查集的根再查询。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,q,fa[100005],id[10000005],rt[100005],tot;
struct node
{
    int ls,rs,sum;
}tree[10000005];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline int find(int x)
{
    if (x==fa[x]) return x;
    return fa[x]=find(fa[x]);
}
inline int build(int index,int l,int r,int pos,int idx)
{
    if (!index) index=++tot;
    if (l==r){id[index]=idx;tree[index].sum++;return index;}
    int mid=(l+r)>>1;
    if (pos<=mid) tree[index].ls=build(tree[index].ls,l,mid,pos,idx);
    else tree[index].rs=build(tree[index].rs,mid+1,r,pos,idx);
    tree[index].sum=tree[tree[index].ls].sum+tree[tree[index].rs].sum;
    return index;
}
inline int merge(int x,int y,int l,int r)
{
    if (!x) return y;
    if (!y) return x;
    if (l==r){if (id[y]){id[x]=id[y];tree[x].sum+=tree[y].sum;}return x;} 
    int mid=(l+r)>>1;
    tree[x].ls=merge(tree[x].ls,tree[y].ls,l,mid);
    tree[x].rs=merge(tree[x].rs,tree[y].rs,mid+1,r);
    tree[x].sum=tree[tree[x].ls].sum+tree[tree[x].rs].sum;
    return x;
}
inline int query(int index,int x,int l,int r)
{
    if (tree[index].sum<x||!index) return 0;
    if (l==r) return id[index];
    int mid=(l+r)>>1,ans;
    if (x<=tree[tree[index].ls].sum) ans=query(tree[index].ls,x,l,mid);
    else ans=query(tree[index].rs,x-tree[tree[index].ls].sum,mid+1,r);
    return ans;
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=n;i++)
    {
        fa[i]=i;int x=read();
        rt[i]=build(rt[i],1,n,x,i);
    }
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        x=find(x),y=find(y);
        fa[y]=x;
        rt[x]=merge(rt[x],rt[y],1,n);
    }
    q=read();
    while(q--)
    {
        char c;cin>>c;
        int x=read(),y=read();
        if (c=='B')
        {
            x=find(x),y=find(y);
            if (x==y) continue;
            fa[y]=x;
            rt[x]=merge(rt[x],rt[y],1,n);
        }
        else
        {
            x=find(x);
            int ans=query(rt[x],y,1,n);
            if (!ans) printf("-1\n");
            else printf("%d\n",ans); 
        }
    }
    return 0;
}

 

posted @ 2020-07-21 18:56  我亦如此向往  阅读(128)  评论(0编辑  收藏  举报