[bzoj2733] [HNOI2012] 永无乡

Description

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

\(B\) \(x\) \(y\) 表示在岛 \(x\) 与岛 \(y\) 之间修建一座新桥。
\(Q\) \(x\) \(k\) 表示询问当前与岛 \(x\) 连通的所有岛中第 \(k\) 重要的是哪座岛,即所有与岛 \(x\) 连通的岛中重要度排名第 \(k\) 小的岛是哪 座,请你输出那个岛的编号。

Input

输入文件第一行是用空格隔开的两个正整数 \(n\)\(m\) ,分别 表示岛的个数以及一开始存在的桥数。
接下来的一行是用空格隔开的 \(n\) 个数,依次描述从岛 \(1\) 到岛 \(n\) 的重要度排名。随后的 \(m\) 行每行是用空格隔开的两个正整数 \(ai\)\(bi\),表示一开始就存 在一座连接岛 \(ai\) 和岛 \(bi\) 的桥。后面剩下的部分描述操作,该部分的第一行是一个正整数 \(q\), 表示一共有 \(q\) 个操作,接下来的 \(q\) 行依次描述每个操作,操作的格式如上所述,以大写字母 \(Q\)\(B\) 开始,后面跟两个不超过 \(n\) 的正整数,字母与数字以及两个数字之间用空格隔开。

对于 \(100 \%\) 的数据 \(n \leq 100000,m \leq n,q \leq 300000\)

Output

对于每个 \(Q\) \(x\) \(k\) 操作都要依次输出一行,其中包含一个整数,表示所询问岛屿的编号。如果该岛屿不存在,则输出 \(-1\)

Sample Input

5 1

4 3 2 5 1

1 2

7

Q 3 2

Q 2 1

B 2 3

B 1 5

Q 2 1

Q 2 4

Q 2 3

Sample Output

-1

2

5

1

2


想法

是一道标准的线段树合并模板。

用并查集维护连通性,权值线段树维护每个联通块中的所有权值。
加边时如果要连接两个并查集,则两个权值线段树合并。

线段树合并的总复杂度不超过 \(nlogn\)


代码

#include<cstdio>
#include<iostream>
#include<algorithm>
 
using namespace std;
 
int read(){
    int x=0;
    char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x;
}
 
const int N = 100005;
 
int n,m;
 
int root[N],cnt,ch[N*18][2],s[N*18];
void insert(int x,int l,int r,int c){
    s[x]++;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(c<=mid) insert(ch[x][0]=++cnt,l,mid,c);
    else insert(ch[x][1]=++cnt,mid+1,r,c);
}
int merge(int x,int y){
    if(!x || !y) return x+y;
    ch[x][0]=merge(ch[x][0],ch[y][0]);
    ch[x][1]=merge(ch[x][1],ch[y][1]);
    s[x]+=s[y];
    return x;
}
int find(int x,int l,int r,int k){
    if(l==r) return l;
    int mid=(l+r)>>1;
    if(s[ch[x][0]]>=k) return find(ch[x][0],l,mid,k);
    return find(ch[x][1],mid+1,r,k-s[ch[x][0]]);
}
 
int fa[N],re[N];
int getfa(int x) { return fa[x]==x ? x : fa[x]=getfa(fa[x]); }
void unit(int x,int y){
    x=getfa(x); y=getfa(y);
    if(x==y) return;
    fa[y]=x; root[x]=merge(root[x],root[y]);
}
 
int main()
{
    int x,k;
    n=read(); m=read();
    for(int i=1;i<=n;i++) {
        fa[i]=i; k=read();
        insert(root[i]=++cnt,1,n,k);
        re[k]=i;
    }
    for(int i=0;i<m;i++) unit(read(),read());
     
    char ch[2];
    m=read();
    while(m--){
        scanf("%s",ch);
        if(ch[0]=='Q'){
            x=getfa(read()); k=read();
            if(s[root[x]]<k) printf("-1\n");
            else printf("%d\n",re[find(root[x],1,n,k)]);
        }
        else unit(read(),read());
    }
     
    return 0;
}

转载于:https://www.cnblogs.com/lindalee/p/11390181.html

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、下4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 、下4载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合;、 4下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值