B20J_2733_[HNOI2012]永无乡_权值线段树合并

B20J_2733_[HNOI2012]永无乡_权值线段树合并

Description:

n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。现在有两种操作:B x y表示在岛 x与岛y之间修建一座新桥。Q x k表示询问当前与岛 x连通的所有岛中第k重要的是哪座岛,即所有与岛 x连通的岛中重要度排名第 k小的岛是哪座,请你输出那个岛的编号。

对于100%的数据n≤100000,m≤n,q≤300000。

分析:读懂题后发现是一道线段树合并的裸题。Q操作显然是权值线段树求区间第k小元素,B操作是合并。

直接开发现开不下,需要动态开点,一开始要开nlogn个结点。

合并操作:

int merge(int x,int y)
{
    if(!x)return y;
    if(!y)return x;
    lson[x]=merge(lson[x],lson[y]);
    rson[x]=merge(rson[x],rson[y]);
    t[x]=t[lson[x]]+t[rson[x]]; 
    return x;
}

 

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=3262145;
int tree[N],lson[N],rson[N],t[N],mp[N],fa[N],idx[N],cnt;
int n,m,k;
char s[10];
int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);    
}
void bt(int l,int r,int val,int &pos)
{
    if(pos==0)pos=++cnt;
    if(l==r)
    {
        t[pos]=1;
        return ;
    }
    int mid=l+r>>1;
    if(val<=mid)bt(l,mid,val,lson[pos]);
    else bt(mid+1,r,val,rson[pos]);
    t[pos]=t[lson[pos]]+t[rson[pos]];
}
int merge(int x,int y)
{
    if(!x)return y;
    if(!y)return x;
    lson[x]=merge(lson[x],lson[y]);
    rson[x]=merge(rson[x],rson[y]);
    t[x]=t[lson[x]]+t[rson[x]]; 
    return x;
}
int query(int l,int r,int k,int pos)
{
    if(l==r||k==0)
    {
        return mp[l];   
    }
    int mid=l+r>>1;
    if(t[pos]<k)return -1;
    if(t[lson[pos]]>=k)
    {
        return query(l,mid,k,lson[pos]);    
    }
    else
    {
        return query(mid+1,r,k-t[lson[pos]],rson[pos]);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        fa[i]=i;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&idx[i]);
        mp[idx[i]]=i;
    }
    for(int i=1;i<=n;i++)
    {
        tree[i]=++cnt;
        bt(1,n,idx[i],tree[i]);
    }
    int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        int dx=find(x),dy=find(y);
        if(dx!=dy)
        {
            fa[dy]=dx;
            tree[dx]=merge(tree[dx],tree[dy]);  
        }   
    }
    scanf("%d",&k);
    while(k--)
    {
        scanf("%s%d%d",s,&x,&y);
        int dx=find(x);
        if(s[0]=='Q')
        {
            printf("%d\n",query(1,n,y,tree[dx]));
        }
        else
        {
            int dx=find(x),dy=find(y);
            if(dx!=dy)
            {
                fa[dy]=dx;
                tree[dx]=merge(tree[dx],tree[dy]);
            }
        }
    }
}
 

 

posted @ 2018-02-04 10:58  fcwww  阅读(253)  评论(0编辑  收藏  举报