【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并
题目描述
.jpg)
输入
第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。
输出
对于每一个第一类操作,输出一个非负整数表示答案。
样例输入
1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6
样例输出
2
2
1
4
2
题解
倍增LCA+主席树+启发式合并
如果没有连边操作,那么本题同 bzoj2588 。
好在本题的n只有80000,所以我们可以使用一些高(qi)端(ji)姿(yin)势(qiao)来解决。
由于只有连边没有删边,所以可以使用启发式合并,暴力将较小的树连到较大的树上,从连接点开始再dfs一遍更新fa和deep。
同时需要记录每棵树的大小,相当于记录每个点的树根。
然后就是建树,求LCA,求出答案。
这里需要注意的一点是,对于不同的倍增LCA的写法,如果写法中利用到f[x][...]=0,那么务必在连边时将原来的f数组清空,否则当原深度大于新深度时会WA->RE。
#include <cstdio>
#include <algorithm>
#define N 80010
using namespace std;
int n , w[N] , a[N] , ref[N] , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][20] , deep[N] , log[N] , bl[N] , si[N];
int ls[N << 8] , rs[N << 8] , sum[N << 8] , root[N] , tot;
char str[5];
void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void insert(int p , int l , int r , int x , int &y)
{
if(!y) y = ++tot;
sum[y] = sum[x] + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) rs[y] = rs[x] , insert(p , l , mid , ls[x] , ls[y]);
else ls[y] = ls[x] , insert(p , mid + 1 , r , rs[x] , rs[y]);
}
int query(int p , int l , int r , int a , int b , int c , int d)
{
if(l == r) return ref[l];
int mid = (l + r) >> 1;
if(sum[ls[a]] + sum[ls[b]] - sum[ls[c]] - sum[ls[d]] >= p) return query(p , l , mid , ls[a] , ls[b] , ls[c] , ls[d]);
else return query(p - sum[ls[a]] - sum[ls[b]] + sum[ls[c]] + sum[ls[d]] , mid + 1 , r , rs[a] , rs[b] , rs[c] , rs[d]);
}
void dfs(int x , int r)
{
int i;
bl[x] = r , si[r] ++ ;
insert(w[x] , 1 , n , root[fa[x][0]] , root[x]);
for(i = 1 ; i <= log[deep[x]] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x][0])
fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i] , r);
}
int lca(int x , int y)
{
int i;
if(deep[x] < deep[y]) swap(x , y);
for(i = log[deep[x] - deep[y]] ; i >= 0 ; i -- )
if(deep[x] - deep[y] >= (1 << i))
x = fa[x][i];
for(i = log[deep[x]] ; i >= 0 ; i -- )
if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i])
x = fa[x][i] , y = fa[y][i];
return x == y ? x : fa[x][0];
}
int main()
{
int m , q , i , t , x , y , z , last = 0;
scanf("%*d%d%d%d" , &n , &m , &q);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &w[i]) , a[i] = w[i];
sort(a + 1 , a + n + 1);
for(i = 1 ; i <= n ; i ++ ) t = w[i] , w[i] = lower_bound(a + 1 , a + n + 1 , w[i]) - a , ref[w[i]] = t;
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
log[0] = -1;
for(i = 2 ; i <= n ; i ++ ) log[i] = log[i >> 1] + 1;
for(i = 1 ; i <= n ; i ++ ) if(!fa[i][0]) dfs(i , i);
while(q -- )
{
scanf("%s%d%d" , str , &x , &y) , x ^= last , y ^= last;
if(str[0] == 'Q')
{
scanf("%d" , &z) , z ^= last , t = lca(x , y);
printf("%d\n" , last = query(z , 1 , n , root[x] , root[y] , root[t] , root[fa[t][0]]));
}
else
{
if(si[bl[x]] < si[bl[y]]) swap(x , y);
fa[y][0] = x , deep[y] = deep[x] + 1 , dfs(y , bl[x]) , add(x , y) , add(y , x);
}
}
return 0;
}
【bzoj3123】[Sdoi2013]森林 倍增LCA+主席树+启发式合并的更多相关文章
- [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)
传送门 突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288 首先有两个操作,一个查询,一个连接 查询的话,直接 ...
- 洛谷 P3302 [SDOI2013]森林 Lebal:主席树 + 启发式合并 + LCA
题目描述 小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有M条边. 小Z希望执行T个操作,操作有两类: Q x y k查询点x到点y路径上所有的权值中,第k小的权 ...
- p3302 [SDOI2013]森林(树上主席树+启发式合并)
对着题目yy了一天加上看了一中午题解,终于搞明白了我太弱了 连边就是合并线段树,把小的集合合并到大的上,可以保证规模至少增加一半,复杂度可以是\(O(logn)\) 合并的时候暴力dfs修改倍增数组和 ...
- 【主席树 启发式合并】bzoj3123: [Sdoi2013]森林
小细节磕磕碰碰浪费了半个多小时的时间 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M ...
- [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...
- 【BZOJ-3123】森林 主席树 + 启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2738 Solved: 806[Submit][Status] ...
- BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并
BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20 ...
随机推荐
- 谈谈我理解的Http缓存机制
前几天看到老铁们分享的面经,谈到 http 缓存机制的问题,痛下决心,一口气研究个明白,分享给大家. 前端的发展越来越迅速,能做的事情越来越多,承担的责任越来越重,通过了解 http 缓存机制,可以帮 ...
- iOS 自定义读写文件
LSCacheFile.h // // LSCacheFile.h // iPhone // // Created by xujinzhong on 14-6-5. // Copyright (c) ...
- 企业CIO、CTO必读的34个经典故事
一. 用人之道 去过庙的人都知道,一进庙门,首先是弥陀佛,笑脸迎客,而在他的北面,则是黑口黑脸的韦陀.但相传在很久以前,他们并不在同一个庙里,而是分别掌管不同的庙.弥乐佛热情快乐,所以来的人非常多,但 ...
- Servlet和JSP之有关Servlet和JSP的梳理(二)
JSP JSP页面本质上是一个Servlet,JSP页面在JSP容器中运行,一个Servlet容器通常也是JSP容器. 当一个JSP页面第一次被请求时,Servlet/JSP容器主要做一下两件事情: ...
- 融云参加RTC实时互联网大会 现场集成IM SDK
9月21至22日,由全球实时云服务商声网Agora.io主办的RTC2017实时互联网大会在北京万豪酒店成功举办.作为亚洲最权威的RTC实时通信行业技术盛会,会议吸引了来自全球上千名开发者参加,Goo ...
- CentOS7——防火墙设置
1.查看firewall服务状态 systemctl status firewalld 2.查看firewall的状态firewall-cmd --state 3.开启.重启.关闭.firewalld ...
- Ajax 发送OPTION请求
从fetch说起,用fetch构造一个POST请求. fetch('http://127.0.0.1:8000/api/login', { method: "POST", head ...
- mask rcnn和roi-align
faster-rcnn的github源码中是round四舍五入 但kaiming he的ppt是直接取整 1.讲roi-align和roi-pooling区别并且详细阐述roi-align过程的博客: ...
- VC-基础:VC++动态链接库(DLL)编程深入浅出
1.概论 先来阐述一下DLL(Dynamic Linkable Library)的概念,你可以简单的把DLL看成一种仓库,它提供给你一些可以直接拿来用的变量.函数或类.在仓库的发展史上经历了“无库-静 ...
- Java简答题附答案
1. Java有没有goto? 有, Goto语句在java中作为保留字, 并没有实现它. 带标号的break, continue局限于循环体中跳转 带标号的goto可以在一个函数(c语言)中任意跳转 ...