• 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
    ",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]);
                }
            }
        }
    }
     
    
  • 相关阅读:
    1.1 控制div属性
    1.7 节点进行排序显示
    [iOS问题归总]iPhone上传项目遇到的问题
    [iOS]iPhone进行真机测试(基础版)
    [iOS]利用Appicon and Launchimage Maker生成并配置iOSApp的图标和启动页
    [cocoapods]cocoapods问题解决
    [cocoapods] 如何卸载工程里的cocoapods
    [iOS]如何把App打包成ipa文件,然后App上架流程[利用Application Loader]
    [iOS]开发者证书和描述文件的作用
    [iOS]解决模拟器无法输入中文问题
  • 原文地址:https://www.cnblogs.com/suika/p/8412673.html
Copyright © 2020-2023  润新知