• [BZOJ] 2733: [HNOI2012]永无乡 #线段树合并+并查集


    2733: [HNOI2012]永无乡

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 4123  Solved: 2196
    [Submit][Status][Discuss]

    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 的正整数,字母与数字以及两个数字之间用空格隔开。 对于 20%的数据 n≤1000,q≤1000 
     
    对于 100%的数据 n≤100000,m≤n,q≤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

    HINT

     

    Source

    Analysis

    啊,这题做的真xx艰难

    qwq

    题目是不难码的,标准的 权值线段树+线段树合并+并查集防重边

    线段树合并,前人之述备矣

    并查集防重边:合并同一棵线段树,也许会有很大几率(100%-eps)出错;为了安全在合并两棵线段树之前需要判断一下是否是联通块

    那么,树顶的编号究竟是要存在哪就有点争议了

    笔者选择保存在并查集里作为公共祖先,这样的话 root[ i ] 就只保存每个结点最初那棵线段树的 rt 编号,而实时的树顶编号则是 find(root[i]) 

    值得一提的是,我写的时候这里并查集居然出事了

    原先写的并查集是 “pre[x]为 0 则为当前点,否则转至pre[x]寻找pre[pre[x]]”
    然而在第7个点发生了RE
    于是改成黄学长风格的并查集
    初始化 pre[x] = x 才算解决了问题
    并查集事故

    此外就没有什么其他问题了

    Code

     1 #include<stdio.h>
     2 #define maxn 1000000
     3 using namespace std;
     4 
     5 int TIM,chart[maxn],root[maxn],n,m,q,rank[maxn];
     6 
     7 struct node{
     8     int L,R,lc,rc,sum;
     9 }T[maxn*5];
    10 
    11 int build(int L,int R,int pos){
    12     int rt = ++TIM;
    13     T[rt].L = L, T[rt].R = R;
    14     if(L == R){ T[rt].sum = 1; return rt; }
    15     int mid = (L+R)>>1;
    16     if(pos <= mid) T[rt].lc = build(L,mid,pos);
    17     else T[rt].rc = build(mid+1,R,pos);
    18     T[rt].sum = T[T[rt].lc].sum+T[T[rt].rc].sum;
    19     return rt;
    20 }
    21 
    22 int query(int rt,int pos){
    23     if(!rt || pos > T[rt].sum) return -1;
    24     if(T[rt].L == T[rt].R) return chart[T[rt].L];
    25     if(pos <= T[T[rt].lc].sum) return query(T[rt].lc,pos);
    26     else return query(T[rt].rc,pos-T[T[rt].lc].sum);
    27 }
    28 
    29 int Merge(int rt_a,int rt_b){
    30     if(!rt_a||!rt_b) return rt_a^rt_b;
    31     T[rt_a].lc = Merge(T[rt_a].lc,T[rt_b].lc);
    32     T[rt_a].rc = Merge(T[rt_a].rc,T[rt_b].rc);
    33     T[rt_a].sum += T[rt_b].sum;
    34     return rt_a;
    35 }
    36 
    37 int pre[maxn*4]; int find(int x){
    38     if(pre[x] == x) return x;
    39     else{ pre[x] = find(pre[x]); return pre[x]; }
    40 }void unite(int u,int v){
    41     if(find(root[u]) == find(root[v]) && root[u] == root[v]) return;
    42     Merge(find(root[u]),find(root[v]));
    43     pre[find(root[v])] = find(root[u]);
    44 }
    45 
    46 void Q(){
    47     int x,k; scanf("%d%d",&x,&k);
    48     int ans = query(find(root[x]),k);
    49     printf("%d
    ",ans);
    50 }
    51 
    52 void B(){
    53     int u,v; scanf("%d%d",&u,&v);
    54     if(!u && !v) return;
    55     unite(u,v);
    56 }
    57 
    58 int main(){
    59 //    freopen("input7.in","r",stdin);
    60 //    freopen("1.out","w",stdout);
    61     
    62     scanf("%d%d",&n,&m);
    63     
    64     for(int i = 1;i <= n;i++){ scanf("%d",&rank[i]); chart[rank[i]] = i; }
    65     
    66     for(int i = 1;i <= n;i++) root[i] = build(1,n,rank[i]),pre[root[i]] = root[i];
    67     
    68     for(int i = 1;i <= m;i++){
    69         int u,v; scanf("%d%d",&u,&v);
    70         if(!u && !v) continue;
    71         unite(u,v);
    72     }
    73     
    74 //    printf("root[34534]: %d
    ",root[34534]);
    75     
    76     scanf("%d",&q);
    77     
    78     for(int i = 1;i <= q;i++){
    79         char ctr[2]; scanf("%s",ctr);
    80         if(ctr[0] == 'Q') Q();
    81         else B();
    82     }return 233;
    83         
    84     return 0;
    85 }
    qwq路途艰险!感谢Onion_cyc帮我要数据
  • 相关阅读:
    linux权限补充:rwt rwT rws rwS 特殊权限
    关于Linux操作系统下文件特殊权限的解释
    Java学习笔记——Java程序运行超时后退出或进行其他操作的实现
    Java实现 蓝桥杯 算法提高 判断名次
    Java实现 蓝桥杯 算法提高 判断名次
    Java实现 蓝桥杯 算法提高 日期计算
    Java实现 蓝桥杯 算法提高 日期计算
    Java实现 蓝桥杯 算法提高 概率计算
    Java实现 蓝桥杯 算法提高 概率计算
    Java实现 蓝桥杯 算法提高 复数四则运算
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7739573.html
Copyright © 2020-2023  润新知