[BZOJ] 2733: [HNOI2012]永无乡 #线段树合并+并查集
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了[BZOJ] 2733: [HNOI2012]永无乡 #线段树合并+并查集,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3448字,纯文字阅读大概需要5分钟。
内容图文
![[BZOJ] 2733: [HNOI2012]永无乡 #线段树合并+并查集](/upload/InfoBanner/zyjiaocheng/1065/4dc50a6de03a43b684060d803c402fe9.jpg)
2733: [HNOI2012]永无乡
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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
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
2
5
1
2
HINT
Source
Analysis
啊,这题做的真xx艰难
qwq
题目是不难码的,标准的 权值线段树+线段树合并+并查集防重边
线段树合并,前人之述备矣
并查集防重边:合并同一棵线段树,也许会有很大几率(100%-eps)出错;为了安全在合并两棵线段树之前需要判断一下是否是联通块
那么,树顶的编号究竟是要存在哪就有点争议了
笔者选择保存在并查集里作为公共祖先,这样的话 root[ i ] 就只保存每个结点最初那棵线段树的 rt 编号,而实时的树顶编号则是 find(root[i])
值得一提的是,我写的时候这里并查集居然出事了
![技术分享](/img/jia.gif)
![技术分享](/img/jian.gif)
原先写的并查集是 “pre[x]为 0 则为当前点,否则转至pre[x]寻找pre[pre[x]]” 然而在第7个点发生了RE 于是改成黄学长风格的并查集 初始化 pre[x] = x 才算解决了问题
此外就没有什么其他问题了
Code
![技术分享](/img/jia.gif)
![技术分享](/img/jian.gif)
1 #include<stdio.h> 2#define maxn 1000000 3usingnamespace std; 4 5int TIM,chart[maxn],root[maxn],n,m,q,rank[maxn]; 6 7struct node{ 8int L,R,lc,rc,sum; 9 }T[maxn*5]; 1011int build(int L,int R,int pos){ 12int rt = ++TIM; 13 T[rt].L = L, T[rt].R = R; 14if(L == R){ T[rt].sum = 1; return rt; } 15int mid = (L+R)>>1; 16if(pos <= mid) T[rt].lc = build(L,mid,pos); 17else T[rt].rc = build(mid+1,R,pos); 18 T[rt].sum = T[T[rt].lc].sum+T[T[rt].rc].sum; 19return rt; 20} 2122int query(int rt,int pos){ 23if(!rt || pos > T[rt].sum) return -1; 24if(T[rt].L == T[rt].R) return chart[T[rt].L]; 25if(pos <= T[T[rt].lc].sum) return query(T[rt].lc,pos); 26elsereturn query(T[rt].rc,pos-T[T[rt].lc].sum); 27} 2829int Merge(int rt_a,int rt_b){ 30if(!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; 34return rt_a; 35} 3637int pre[maxn*4]; int find(int x){ 38if(pre[x] == x) return x; 39else{ pre[x] = find(pre[x]); return pre[x]; } 40 }void unite(int u,int v){ 41if(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} 4546void Q(){ 47int x,k; scanf("%d%d",&x,&k); 48int ans = query(find(root[x]),k); 49 printf("%d\n",ans); 50} 5152void B(){ 53int u,v; scanf("%d%d",&u,&v); 54if(!u && !v) return; 55 unite(u,v); 56} 5758int main(){ 59// freopen("input7.in","r",stdin); 60// freopen("1.out","w",stdout);6162 scanf("%d%d",&n,&m); 6364for(int i = 1;i <= n;i++){ scanf("%d",&rank[i]); chart[rank[i]] = i; } 6566for(int i = 1;i <= n;i++) root[i] = build(1,n,rank[i]),pre[root[i]] = root[i]; 6768for(int i = 1;i <= m;i++){ 69int u,v; scanf("%d%d",&u,&v); 70if(!u && !v) continue; 71 unite(u,v); 72 } 7374// printf("root[34534]: %d\n",root[34534]);7576 scanf("%d",&q); 7778for(int i = 1;i <= q;i++){ 79char ctr[2]; scanf("%s",ctr); 80if(ctr[0] == ‘Q‘) Q(); 81else B(); 82 }return233; 8384return0; 85 }
原文:http://www.cnblogs.com/Chorolop/p/7739573.html
内容总结
以上是互联网集市为您收集整理的[BZOJ] 2733: [HNOI2012]永无乡 #线段树合并+并查集全部内容,希望文章能够帮你解决[BZOJ] 2733: [HNOI2012]永无乡 #线段树合并+并查集所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。