luoguP3302 [SDOI2013]森林
https://www.luogu.org/problemnew/show/P3302
看到查询第 k 小,而且是一颗树,可以联想到在树上的主席树,a 和 b 路径中第 k 小可以通过在 a, b, lca(a, b), fa[lca(a, b)] 四个节点对应的主席树上二分得到
实现主席树是很简单的,连接两个点可以启发式合并,现在最大的问题是连接两个点后还要高效的求出 LCA,一种做法是启发式合并的时候重构倍增数组,也有一种用 LCT 维护 LCA 的方法,相对简单。博主的实现是后者
需要注意的就是找到 fa[lca(a, b)] 的时候,可以模仿 LCT findroot 函数的实现,先 access(lca),然后 splay(lca),找到深度次大的点即可。link 之后 root 会变,进行新操作的时候要 makeroot,才能求出正确的 LCA
总而言之,需要注意的细节还是很多的,具体还是看代码实现吧
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
template <typename _T>
inline void read(_T &f) {
f = 0; _T fu = 1; char c = getchar();
while(c < '0' || c > '9') {if(c == '-') fu = -1; c = getchar();}
while(c >= '0' && c <= '9') {f = (f << 3) + (f << 1) + (c & 15); c = getchar();}
f *= fu;
}
const int N = 80000 + 10;
int fa[N], ch[N][2], rev[N], st[N], len;
int n, m, t;
int isroot(int u) {return ch[fa[u]][0] != u && ch[fa[u]][1] != u;}
int get(int u) {return ch[fa[u]][1] == u;}
void pushdown(int u) {
if(rev[u]) {
swap(ch[u][0], ch[u][1]);
rev[ch[u][0]] ^= 1;
rev[ch[u][1]] ^= 1;
rev[u] ^= 1;
}
}
void rotate(int u) {
int old = fa[u], oldd = fa[old], k = get(u);
if(!isroot(old)) ch[oldd][get(old)] = u; fa[u] = oldd;
fa[ch[u][k ^ 1]] = old; ch[old][k] = ch[u][k ^ 1];
fa[old] = u; ch[u][k ^ 1] = old;
}
void splay(int u) {
st[len = 1] = u;
for(int i = u; !isroot(i); i = fa[i]) st[++len] = fa[i];
for(int i = len; i >= 1; i--) pushdown(st[i]);
for(; !isroot(u); rotate(u)) if(!isroot(fa[u])) rotate(get(u) == get(fa[u]) ? fa[u] : u);
}
int access(int u) {
int tmp;
for(int i = 0; u; i = u, u = fa[u]) {
splay(u);
ch[u][1] = i;
tmp = u;
}
return tmp;
}
void makeroot(int u) {
access(u);
splay(u);
rev[u] ^= 1;
}
void link(int x, int y) {
makeroot(x);
fa[x] = y;
}
int LCA(int x, int y) {
access(x);
return access(y);
}
int rt[N], val[N * 600], lc[N * 600], rc[N * 600], a[N], b[N];
int tot = 0;
void build(int &u, int l, int r) {
u = ++tot;
if(l == r) return;
int mid = (l + r) >> 1;
build(lc[u], l, mid);
build(rc[u], mid + 1, r);
}
void ins(int &u, int pre, int l, int r, int x) {
u = ++tot;
val[u] = val[pre] + 1, lc[u] = lc[pre], rc[u] = rc[pre];
if(l == r) return;
int mid = (l + r) >> 1;
if(mid >= x) ins(lc[u], lc[pre], l, mid, x);
else ins(rc[u], rc[pre], mid + 1, r, x);
}
int query(int a, int b, int c, int d, int l, int r, int k) {
if(l == r) return l;
int lsum = val[lc[a]] + val[lc[b]] - val[lc[c]] - val[lc[d]];
int rsum = val[rc[a]] + val[rc[b]] - val[rc[c]] - val[rc[d]];
int mid = (l + r) >> 1;
if(lsum >= k) return query(lc[a], lc[b], lc[c], lc[d], l, mid, k);
else return query(rc[a], rc[b], rc[c], rc[d], mid + 1, r, k - lsum);
}
int blen;
vector <int> g[N];
int siz[N], head[N];
int f[N]; int find(int x) {return f[x] == x ? x : f[x] = find(f[x]);}
inline void addedge(int u, int v) {
g[u].push_back(v);
g[v].push_back(u);
}
void dfs1(int u, int f) {
ins(rt[u], rt[f], 1, blen, a[u]);
for(vector <int> :: iterator it = g[u].begin(); it != g[u].end(); it++) {
int v = *it; if(v == f) continue; dfs1(v, u);
}
}
void Merge(int a, int b) {
int x = find(a), y = find(b);
if(siz[x] < siz[y]) swap(a, b), swap(x, y);
siz[x] += siz[y]; addedge(a, b);
link(a, b); f[y] = x;
dfs1(b, a);
}
int lastans = 0;
int main() {
cin >> n;
cin >> n >> m >> t;
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
b[i] = a[i];
f[i] = i; siz[i] = 1;
}
sort(b + 1, b + n + 1);
blen = unique(b + 1, b + n + 1) - b - 1;
for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + blen + 1, a[i]) - b;
build(rt[0], 1, blen);
for(int i = 1; i <= n; i++) {
ins(rt[i], rt[0], 1, blen, a[i]);
}
for(int i = 1; i <= m; i++) {
int A, B;
scanf("%d %d", &A, &B);
Merge(A, B);
}
for(int i = 1; i <= t; i++) {
char c = getchar();
while(c != 'Q' && c != 'L') c = getchar();
if(c == 'L') {
int A, B;
scanf("%d %d", &A, &B);
A ^= lastans; B ^= lastans;
Merge(A, B);
} else {
int A, B, K;
scanf("%d %d %d", &A, &B, &K);
A ^= lastans; B ^= lastans; K ^= lastans;
makeroot(find(A));
int lca = LCA(A, B), father;
if(find(A) == lca) father = 0;
else {
access(lca); splay(lca);
father = ch[lca][0];
while(ch[father][1]) {
father = ch[father][1];
pushdown(father);
}
}
printf("%d\n", lastans = b[query(rt[A], rt[B], rt[lca], rt[father], 1, blen, K)]);
}
}
return 0;
}
luoguP3302 [SDOI2013]森林的更多相关文章
- luoguP3302 [SDOI2013]森林 主席树 启发式合并
题目链接 luoguP3302 [SDOI2013]森林 题解 本来这题树上主席树暴力启发式合并就完了 结果把lca写错了... 以后再也不这么写了 复杂度\(O(nlog^2n)\) "f ...
- [luoguP3302] [SDOI2013]森林(主席树 + 启发式合并 + lca)
传送门 显然树上第k大直接主席树 如果连边的话,我们重构小的那一棵,连到另一棵上. 说起来简单,调了我一晚上. 总的来说3个错误: 1.离散化写错位置写到了后面 2."="写成了& ...
- BZOJ 3123: [Sdoi2013]森林 [主席树启发式合并]
3123: [Sdoi2013]森林 题意:一个森林,加边,询问路径上k小值.保证任意时刻是森林 LCT没法搞,树上kth肯定要用树上主席树 加边?启发式合并就好了,小的树dfs重建一下 注意 测试点 ...
- P3302 [SDOI2013]森林(主席树+启发式合并)
P3302 [SDOI2013]森林 主席树+启发式合并 (我以前的主席树板子是错的.......坑了我老久TAT) 第k小问题显然是主席树. 我们对每个点维护一棵包含其子树所有节点的主席树 询问(x ...
- [BZOJ3123][Sdoi2013]森林 主席树+启发式合并
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MB Description Input 第一行包含一个正整数testcase,表示当 ...
- BZOJ3123: [Sdoi2013]森林(启发式合并&主席树)
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4813 Solved: 1420[Submit][Status ...
- 【BZOJ3123】[Sdoi2013]森林 主席树+倍增LCA+启发式合并
[BZOJ3123][Sdoi2013]森林 Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整 ...
- 洛谷 P3302 [SDOI2013]森林 解题报告
P3302 [SDOI2013]森林 题目描述 小\(Z\)有一片森林,含有\(N\)个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有\(M\)条边. 小Z希望执行\(T\)个操作,操 ...
- 3123: [Sdoi2013]森林
3123: [Sdoi2013]森林 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 3336 Solved: 978[Submit][Status] ...
随机推荐
- python与桶排序
问题提出: 将以下数据: 6, 8, 2, 3, 4, 0, 9, 1, 5,1 按从小到达排列. 桶排序原理: 桶排序也叫计数排序,简单来说,就是将数据集里面所有元素按顺序列举出来,然后统计元素出现 ...
- RabbitMQ操作方法
/// <summary> /// 消费者(消息) /// </summary> public class CustmerMq { /// <summary> // ...
- Wcf调用方式
C#动态调用WCF接口,两种方式任你选. 写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去 ...
- mahout in Action2.2-给用户推荐图书(2)-分析对用户推荐书目的结果
2.2.3 Analyzing the output 在之前的程序运行结果中我们得到的结果输出是: RecommendedItem [item:104, value:4.257081] 程序要求选择一 ...
- 判定元素是否刚插入到DOM树
上接<这篇博文>,其应用于avalon的if绑定.如果一个节点还没有插入DOM树,那么avalon将延时对它进行扫描渲染,直到它再次插入到DOM树为止.由于CSS3 keyframe动画的 ...
- mysql\redis局域网链接
mysql: GRANT SELECT,DELETE,UPDATE,INSERT ON int_worm.* TO 'root'@'%' IDENTIFIED BY 'root'; redis: co ...
- Apache Hive 简介及安装
简介 Hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件 映射为一张数据库表,并提供类 SQL 查询功能. 本质是将 SQL 转换为 MapReduce 程序. 主要用途:用来 ...
- 图论算法》关于SPFA和Dijkstra算法的两三事
本来我是想把这两个算法分开写描述的,但是SPFA其实就是Dijkstra的稀疏图优化,所以其实代码差不多,所以就放在一起写了. 因为SPFA是Dijkstra的优化,所以我想来讲讲Dijkstra. ...
- 【bzoj1019】[SHOI2008]汉诺塔
1019: [SHOI2008]汉诺塔 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1427 Solved: 872[Submit][Status] ...
- linux上搭建图片服务器
之前写过一个搭建图片服务器的随笔:https://www.cnblogs.com/xujingyang/p/7163290.html ,现在回头看看,我去,感觉写的好乱,现在再整一个吧.o(╯□╰ ...