zoukankan      html  css  js  c++  java
  • [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
    ");
                    continue;
                }
                a=findfa(a);
                if(siz[rt[a]]<b)
                {
                    printf("-1
    ");
                    continue;
                }else
                {
                    printf("%d
    ",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;
    }
  • 相关阅读:
    复制网页的按钮
    网站需要显示在线访问人数
    文章内容分页功能实现
    重构下拉菜单(DropDownList)与数据源(DataSource)
    使用RenderControl方法实现动态加载用户控件
    BusinessFrameWork Version2
    根据值(value)获取泛型Dictionary的键(key)
    RadioButtonList控件绑定图片Vertical对齐
    CGI和BOA使用期间遇到的问题汇总(转)
    CGI编程学习2 简单练习
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/9824509.html
Copyright © 2011-2022 走看看