[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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM