题意:给定森林,可以把两棵树连起来或者询问链上第k大。

解:启发式合并。

我一开始想到了启发式合并但是发现这样做之后一棵子树就不是一段连续的区间了,那就不能子树xxx了,很迷惘。

后来看了题解发现本来就不需要子树是连续区间......

每次把小的树暴力DFS重构fa[][]和重建主席树。

调了半天是因为lastans没有套上X[]......

注意并查集merge的时候可能有元素为0。无视之即可。

 #include <cstdio>
#include <algorithm> const int N = , M = ; struct Edge {
int nex, v;
}edge[N << ]; int top; int X[N], e[N], n, val[N], temp, pw[N], fa[N][], tot, vis[N], father[N], siz[N], d[N], rt[N];
int sum[M], ls[M], rs[M];
char str[]; int find(int x) {
if(father[x] == x) {
return x;
}
return father[x] = find(father[x]);
} inline void merge(int x, int y) {
if(!x || !y) {
return;
}
x = find(x);
y = find(y);
if(x == y) {
return;
}
father[x] = y;
siz[y] += siz[x];
return;
} inline bool check(int x, int y) {
return find(x) == find(y);
} inline void add(int x, int y) {
top++;
edge[top].v = y;
edge[top].nex = e[x];
e[x] = top;
return;
} void add(int x, int &y, int p, int l, int r) {
if(!y || y == x) {
y = ++tot;
sum[y] = sum[x];
ls[y] = ls[x];
rs[y] = rs[x];
}
if(l == r) {
sum[y]++;
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
add(ls[x], ls[y], p, l, mid);
}
else {
add(rs[x], rs[y], p, mid + , r);
}
sum[y] = sum[ls[y]] + sum[rs[y]];
return;
} void DFS(int x, int f) {
merge(x, f);
vis[x] = ;
fa[x][] = f;
d[x] = d[f] + ;
for(int j = ; j <= pw[n]; j++) {
fa[x][j] = fa[fa[x][j - ]][j - ];
}
rt[x] = ;
add(rt[f], rt[x], val[x], , temp);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(y == f) {
continue;
}
DFS(y, x);
}
return;
} inline void link(int x, int y) {
if(check(x, y)) {
printf("E1");
exit();
}
if(siz[find(x)] < siz[find(y)]) {
std::swap(x, y);
}
DFS(y, x);
add(x, y);
add(y, x);
return;
} inline int lca(int x, int y) {
if(d[x] > d[y]) {
std::swap(x, y);
}
int t = pw[n];
while(t >= && d[x] != d[y]) {
if(d[fa[y][t]] >= d[x]) {
y = fa[y][t];
}
t--;
}
if(x == y) {
return x;
}
t = pw[n];
while(t >= && fa[x][] != fa[y][]) {
if(fa[x][t] != fa[y][t]) {
x = fa[x][t];
y = fa[y][t];
}
t--;
}
return fa[x][];
} int Ask(int x, int y, int z, int w, int k, int l, int r) {
if(l == r) {
return r;
}
int mid = (l + r) >> , s = ;
s = sum[ls[x]] + sum[ls[y]] - sum[ls[z]] - sum[ls[w]];
if(k <= s) {
return Ask(ls[x], ls[y], ls[z], ls[w], k, l, mid);
}
else {
return Ask(rs[x], rs[y], rs[z], rs[w], k - s, mid + , r);
}
} inline int ask(int x, int y, int k) {
if(!check(x, y)) {
printf("E2");
exit();
}
int z = lca(x, y);
if(d[x] + d[y] - d[z] - d[z] + < k) {
printf("E3");
exit();
}
return Ask(rt[x], rt[y], rt[z], rt[fa[z][]], k, , temp);
} int main() { //freopen("in.in", "r", stdin);
//freopen("my.out", "w", stdout); int m, q;
scanf("%d", &n);
scanf("%d%d%d", &n, &m, &q);
for(int i = ; i <= n; i++) {
scanf("%d", &val[i]);
X[++temp] = val[i];
siz[i] = ;
father[i] = i;
}
for(int i = , x, y; i <= m; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
for(int i = ; i <= n; i++) {
pw[i] = pw[i >> ] + ;
}
std::sort(X + , X + temp + );
temp = std::unique(X + , X + temp + ) - X - ;
for(int i = ; i <= n; i++) {
val[i] = std::lower_bound(X + , X + temp + , val[i]) - X;
}
for(int i = ; i <= n; i++) {
if(!vis[i]) {
DFS(i, );
}
}
/// build int lastans = ;
for(int i = , x, y, k; i <= q; i++) {
scanf("%s%d%d", str, &x, &y);
if(str[] == 'L') { // link
link(x ^ lastans, y ^ lastans);
}
else {
scanf("%d", &k);
lastans = X[ask(x ^ lastans, y ^ lastans, k ^ lastans)];
printf("%d\n", lastans);
}
} return ;
}

AC代码

洛谷P3302 森林的更多相关文章

  1. 洛谷$P3302$ 森林 $[SDOI2013]$ 主席树

    正解:主席树 解题报告: 传送门! 口胡一时爽代码火葬场 这题想法不难,,,但显然的是代码应该还挺难打的 但反正我也不放代码,就写下题解趴$QwQ$ 第一问就是个$Count\ on\ a\ tree ...

  2. 洛谷 P3302 [SDOI2013]森林 解题报告

    P3302 [SDOI2013]森林 题目描述 小\(Z\)有一片森林,含有\(N\)个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有\(M\)条边. 小Z希望执行\(T\)个操作,操 ...

  3. 洛谷 P3302 [SDOI2013]森林 Lebal:主席树 + 启发式合并 + LCA

    题目描述 小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有M条边. 小Z希望执行T个操作,操作有两类: Q x y k查询点x到点y路径上所有的权值中,第k小的权 ...

  4. [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)

    传送门 突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288 首先有两个操作,一个查询,一个连接 查询的话,直接 ...

  5. 洛谷 P3302 [SDOI2013]森林

    ->题目链接 题解: #include<queue> #include<cstdio> #include<cstring> #include<iostr ...

  6. 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)

    洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不 ...

  7. 洛谷3月月赛 R1 Step! ZERO to ONE

    洛谷3月月赛 R1 Step! ZERO to ONE 普及组难度 290.25/310滚粗 t1 10分的日语翻译题....太难了不会... t2 真·普及组.略 注意长为1的情况 #include ...

  8. 洛谷P3203 [HNOI2010]弹飞绵羊(LCT,Splay)

    洛谷题目传送门 关于LCT的问题详见我的LCT总结 思路分析 首先分析一下题意.对于每个弹力装置,有且仅有一个位置可以弹到.把这样的一种关系可以视作边. 然后,每个装置一定会往后弹,这不就代表不存在环 ...

  9. 洛谷P4155 [SCOI2015]国旗计划(贪心,树形结构,基数排序)

    洛谷题目传送门 \(O(n)\)算法来啦! 复杂度优化的思路是建立在倍增思路的基础上的,看看楼上几位巨佬的描述吧. 首先数组倍长是一样的.倍增法对于快速找到\(j\)满足\(l_j+m\le r_i\ ...

随机推荐

  1. Git配置用户名与邮箱

    1.用户名和邮箱地址的作用 用户名和邮箱地址是本地git客户端的一个变量 每次commit都会用用户名和邮箱纪录. github的contributions统计就是按邮箱来统计的. 2.查看用户名和邮 ...

  2. 蓝牙Remove Bond的流程分析

    此篇文章简单分析一下蓝牙解除配对在协议栈中的工作流程.分析的协议栈版本是Android8.0 协议栈的接口都定义在bluetooth.cc这个文件中: static int remove_bond(c ...

  3. PowerBI开发 第八篇:查询参数

    在PowerBI Desktop中,用户可以定义一个或多个查询参数(Query Parameter),参数的功能是为了实现PowerBI的参数化编程,使得Data Source的属性.替换值和过滤数据 ...

  4. Asp.Net_Wcf跟Wpf的区别

    摘要:WCF,你就先把它想成WebService的下一代也没什么问题.WCF为WindowsCommunicationFoundation,是Microsoft为构建面向服务的应用提供的分布式通信编程 ...

  5. VS 远程调试 Azure Web App

    如果能够远程调试部署在 Azure 上的 Web App,将会极大的提高我们修复 bug 的效率.Visual Studio 一贯以功能强大.好用著称,当然可以通吃基于 Azure 应用的创建.发布和 ...

  6. 再探Redux Middleware

    前言 在初步了解Redux中间件演变过程之后,继续研究Redux如何将中间件结合.上次将中间件与redux硬结合在一起确实有些难看,现在就一起看看Redux如何加持中间件. 中间件执行过程 希望借助图 ...

  7. PHPMyWind5.4存储XSS后续getshell提权

    0x0 前言 通过留言处的xss,我们可以得到管理员的cookie,进而登陆后台: https://www.cnblogs.com/Rain99-/p/10701769.html 现在要从后台入手,进 ...

  8. Linux内核分析第一周总结

    冯诺依曼体系结构 储存程序计算机工作模型 硬件 程序员 CPU当作for循环: IP: 16位计算机:IP 32位计算机:eIP 64位计算机:rIP X86汇编基础 X86的CPU寄存器 X86的C ...

  9. Git 笔记——如何处理分支合并冲突

    1.前言 学习使用 Git 也有一段时间,但一直都是把 Git 当作一个代码仓库,使用的命令无非就是 clone, add, commit ,往往课程作业也没有过多人合作开发,没有体验过 Git 的分 ...

  10. C# winform打开文件夹并选中指定文件

    例如:打开“E:\Training”文件夹并选中“20131250.html”文件 System.Diagnostics.Process.Start("Explorer.exe", ...