[HNOI2012]永无乡

题目描述

永无乡包含 n 座岛,编号从 1 到 n ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 a 出发经过若干座(含 0 座)桥可以 到达岛 b ,则称岛 a 和岛 b 是连通的。

现在有两种操作:

B x y 表示在岛 x 与岛 y 之间修建一座新桥。

Q x k 表示询问当前与岛 x 连通的所有岛中第 k 重要的是哪座岛,即所有与岛 x 连通的岛中重要度排名第 k 小的岛是哪座,请你输出那个岛的编号。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

题解:线段树合并。对每个点开一棵权值线段树,用并查集维护联通性。

代码:

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100050
int n,m,q;
int fa[N],ch[70*N][2],siz[70*N],tot,rt[N];
char s[10];
int findfa(int x)
{
    if(fa[x]==x)return x;
    return fa[x]=findfa(fa[x]);
}
void update(int x)
{
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]];
}
int ans[N];
void merge(int &x,int y,int l,int r)
{
    if(!y)return ;
    if(!x){x=y;return ;}
    if(l==r){siz[x]=siz[y];return ;}
    int mid = (l+r)>>1;
    merge(ch[x][0],ch[y][0],l,mid);
    merge(ch[x][1],ch[y][1],mid+1,r);
    update(x);
}
void insert(int l,int r,int &u,int x)
{
    u=++tot;
    siz[u]=1;
    if(l==r){return ;}
    int mid = (l+r)>>1;
    if(x<=mid)insert(l,mid,ch[u][0],x);
    else insert(mid+1,r,ch[u][1],x);
}
int query(int l,int r,int u,int k)
{
    if(l==r)return ans[l];
    int tmp = siz[ch[u][0]];
    int mid = (l+r)>>1;
    if(tmp>=k)return query(l,mid,ch[u][0],k);
    else return query(mid+1,r,ch[u][1],k-tmp);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int x,i=1;i<=n;i++)
    {
        scanf("%d",&x);
        insert(1,n,rt[i],x);
        ans[x]=i;
    }
    for(int u,v,i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        int f1 = findfa(u),f2 = findfa(v);
        if(f1!=f2)
        {
            fa[f2]=f1;
            merge(rt[f1],rt[f2],1,n);
        }
    }
    scanf("%d",&q);
    for(int a,b,i=1;i<=q;i++)
    {
        scanf("%s%d%d",s+1,&a,&b);
        if(s[1]=='Q')
        {
            if(a>n)
            {
                printf("-1\n");
                continue;
            }
            a=findfa(a);
            if(siz[rt[a]]<b)
            {
                printf("-1\n");
                continue;
            }else
            {
                printf("%d\n",query(1,n,rt[a],b));
            }
        }else
        {
            int f1 = findfa(a),f2 = findfa(b);
            if(f1!=f2)
            {
                fa[f2]=f1;
                merge(rt[f1],rt[f2],1,n);
            }
        }
    }
    return 0;
}

 

posted @ 2018-10-21 11:54  LiGuanlin  阅读(212)  评论(11编辑  收藏  举报