luoguP3302 [SDOI2013]森林 主席树 启发式合并
题目链接
题解
本来这题树上主席树暴力启发式合并就完了
结果把lca写错了...
以后再也不这么写了
复杂度\(O(nlog^2n)\)
"for(int i = 0;dad[x][i];++ i) dad[x][i+1] = dad[dad[x][i]][i]"
De了两个多小时....QAQ
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
inline int read() {
int x = 0,f = 1;
char c = getchar();
while(c < '0' || c > '9') {if(c == '-')f = -1;c = getchar(); }
while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar();
return x * f;
}
const int maxn = 100007;
struct NNnode {
int v,next;
} edge[maxn << 2];
int num = 0,head[maxn];
inline void add_edge(int u,int v) {
edge[++ num].v = v; edge[num].next = head[u]; head[u] = num;
}
int root[maxn],val[maxn],n,m,t,MX;
int tot = 0;
int ls[40000000],rs[40000000],cnt[40000000];
void insert(int pre,int &now,int l,int r,int key) {
cnt[++ tot] = cnt[now]; now = tot;
++ cnt[now];
if(l == r) return ;
int mid = l + r >> 1;
ls[now] = ls[pre]; rs[now] = rs[pre];
if(key <= mid) insert(ls[pre],ls[now],l,mid,key);
else insert(rs[pre],rs[now],mid + 1,r,key);
}
int query(int t1,int t2,int t3,int t4,int l,int r,int k) {
if (l == r) return l;
int mid = l + r >> 1;
int dtl = cnt[ls[t1]] + cnt[ls[t2]] - cnt[ls[t3]] - cnt[ls[t4]];
if(k <= dtl) return query(ls[t1],ls[t2],ls[t3],ls[t4],l,mid,k);
else return query(rs[t1],rs[t2],rs[t3],rs[t4],mid + 1,r,k - dtl);
}
int root_num[maxn],siz[maxn], dep[maxn],dad[maxn][25];
void dfs(int x) {
siz[x] = 1;
for(int i = 1;i < 20;++i)
dad[x][i] = dad[dad[x][i - 1]][i - 1];
insert(root[dad[x][0]],root[x],1,MX,val[x]);
for(int i = head[x];i;i = edge[i].next) {
int v = edge[i].v;
if(v == dad[x][0]) continue;
root_num[v] = root_num[x];
dad[v][0] = x; dep[v] = dep[x] + 1;
dfs(v);
siz[x] += siz[v];
}
}
int LCA(int x,int y) {
if(dep[x] > dep[y]) std::swap(x,y);
for(int i = 19;i >= 0;i --) if(dep[dad[y][i]] >= dep[x]) y = dad[y][i];
if(x == y) return x;
for(int i = 19;i >= 0;i --) if(dad[y][i] != dad[x][i]) y = dad[y][i],x = dad[x][i];
return dad[x][0];
}
int work_q(int x,int y,int k) {
int lca = LCA(x,y);
int F_lca = dad[lca][0];
return query(root[x],root[y],root[lca],root[dad[lca][0]],1,MX,k);
}
void work_L(int x,int y) {
//printf("%d ***** %d\n",x,y);
if(siz[root_num[x]] < siz[root_num[y]]) std::swap(x,y);
dad[y][0] = x;
siz[root_num[x]] += siz[root_num[y]];
root_num[y] = root_num[x];
dep[y] = dep[x] + 1; add_edge(x,y);add_edge(y,x);
dfs(y);
}
int b[maxn];
void solve() {
tot = MX = 0;
n = read(),m = read(); t = read();
for(int i = 1;i <= n;++ i) b[i] = val[i] = read(),MX = std::max(val[i],MX);
std::sort(b + 1,b + n + 1);
int len = std::unique(b + 1,b + n + 1) - b - 1;
for(int i = 1;i <= n;++ i) val[i] = std::lower_bound(b + 1,b + len + 1,val[i]) - b,MX = std::max(val[i],MX);
for(int x,y,i = 1;i <= m;++ i) {
x = read(), y = read();
add_edge(x,y) , add_edge(y,x);
}
for(int i = 1;i <= n;++ i)
if(!root_num[i]) root_num[i] = i,dep[i] = 1,dfs(i);
char opt[20];
int lans = 0;
while(t --) {
scanf("%s",opt + 1) ;
if(opt[1] == 'Q') {
int x = read() ^ lans,y = read() ^ lans, k = read() ^ lans;
//printf("%d **** %d *** %d *** &&&\n",x,y,lans);
printf("%d\n",lans = b[work_q(x,y,k)]);
} else {
int x = read() ,y = read() ;
x ^= lans,y ^= lans;
//printf("%d **** %d *** %d *** ***\n",x,y,lans);
work_L(x,y);
}
}
}
int main() {
int testcase = read(); //whattttt the fucccck?
testcase = 1;
for(int i = 1;i <= testcase;++ i) solve();
}
luoguP3302 [SDOI2013]森林 主席树 启发式合并的更多相关文章
- Bzoj 3123: [Sdoi2013]森林(主席树+启发式合并)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当前 ...
- [bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...
- [BZOJ3123][Sdoi2013]森林 主席树+启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当 ...
- [SDOI2013]森林 主席树+启发式合并
这题的想法真的很妙啊. 看到题的第一眼,我先想到树链剖分,并把\(DFS\)序当成一段区间上主席树.但是会发现在询问的时候,可能会非常复杂,因为你需要把路径拆成很多条轻链和重链,它们还不一定连续,很难 ...
- 【BZOJ 3123】 [Sdoi2013]森林 主席树启发式合并
我们直接按父子关系建主席树,然后记录倍增方便以后求LCA,同时用并查集维护根节点,而且还要记录根节点对应的size,用来对其启发式合并,然后每当我们合并的时候我们都要暴力拆小的一部分重复以上部分,总时 ...
- 【BZOJ-3123】森林 主席树 + 启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2738 Solved: 806[Submit][Status] ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
- BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并
BZOJ_3123_[Sdoi2013]森林_主席树+启发式合并 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20 ...
随机推荐
- 第一个FPGA工程—LED流水灯
这一章我们来实现第一个FPGA工程-LED流水灯.我们将通过流水灯例程向大家介绍一次完整的FPGA开发流程,从新建工程,代码设计,综合实现,管脚约束,下载FPGA程序.掌握本章内容,大家就算正式的开始 ...
- JavaScript中 this 的指向
很多人都会被JavaScript中this的指向(也就是函数在调用时的调用上下文)弄晕,这里做一下总结: 首先,顶层的this指向全局对象. 函数中的this按照调用方法的不同,其指向也不同: 1.函 ...
- ARMV8 datasheet学习笔记4:AArch64系统级体系结构之Self-hosted debug
1. 前言 2. 关于self-hosted debug Debugger调试器 是操作系统或系统软件的一部分,它会处理debug exception或修改debug system register, ...
- 经典]Linux内核中ioremap映射的透彻理解【转】
转自:http://blog.csdn.net/lanyang123456/article/details/7403514 几乎每一种外设都是通过读写设备上的寄存器来进行的,通常包括控制寄存器.状态寄 ...
- exp自动备份在bat中不执行
在命令行前加cd c:\users\...... 先定位进入可以exp的目录下,再执行exp
- zabbix监控短信息接口是否正常
1.创建Web scenarios 2.创建zabbix触发器name:short_message send status is not 100 Expression:{u04zbx01.yaya.c ...
- PYTHON-模块-time&datetime-练习 +目录规范
# 作业# 1.请写出规范目录# 并解释各文件夹的作用bin 可执行文件conf 配置文件core 主要业务逻辑db 数据文件lib 库(公共代码 第三方模块)log 日志文件 # 2.改造atm + ...
- java比较两个对象是否相等?
1.判断两个对象是否是同一个引用对象则用==,"=="比的是地址.因为如果地址相同,则就是同一个对象(java中如果两对象(obj1,obj2)相等,那么在修改obj2的时候,ob ...
- MyEclipse 2017 ci6 安装反编译插件(本人自己摸索的方法,亲测可行)
注: 本文来源于:Smile_Miracle 的< MyEclipse 2017 ci6 安装反编译插件(本人自己摸索的方法,亲测可行) > 第一步:关闭ME,去一下地址下载jad的反编译 ...
- js获取精确的元素宽高(普通获取高度会有误差)
当js获取元素宽高时, 并不是一个精确的数字,如果想获取真正的宽高大致方法如下 var oStyle = obj.currentStyle ? obj.currentStyle : window.ge ...