题意:给定森林,可以把两棵树连起来或者询问链上第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. web窗体的运用

    using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace WebAp ...

  2. 《图说VR入门》——DeepoonVR的大鹏(陀螺仪)枪

    <图说VR入门>--VR大朋的(陀螺仪)枪 本文章由cartzhang编写,转载请注明出处. 所有权利保留. 文章链接: http://blog.csdn.net/cartzhang/ar ...

  3. Ubuntu中程序部署时无法加载动态库的解决方法

    Ubuntu下修改环境变量的三种方法 添加环境变量无法解决,可尝试如下操作: sudo vim /etc/ld.so.conf 在ld.so.conf中加入动态库的目录... 然后 sudo ldco ...

  4. kvm虚拟化一: 图形化的管理方式

    1.安装必要工具yum install -y / qemu-kvm //kvm主程序 libvirt //虚拟化服务库 libguestfs-tools //虚拟机系统管理工具 virt-instal ...

  5. [LOJ#6066]. 「2017 山东一轮集训 Day3」第二题[二分+括号序列+hash]

    题意 题目链接 分析 首先二分,假设二分的答案为 \(mid\),然后考虑利用括号序列来表示树的形态. 点 \(u\) 的 \(k-\) 子树的括号序列表示实际上是刨去了 \(u\) 子树内若干个与 ...

  6. 搭建SpringBoot、Jsp支持学习笔记

    Spring Boot 添加JSP支持 大体步骤: (1)            创建Maven web project: (2)            在pom.xml文件添加依赖: (3)     ...

  7. muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor

    目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...

  8. 01_python2.x和python3.x中range()的区别

    Py2.x 1) .range 和xrange都是经常使用的,特别是range()返回一个列表 2) .xrange()一般用来创建迭代对象 Py3.x xrange()不存在了,只有range()而 ...

  9. JavaScript高级程序设计学习笔记2

    垃圾收集原理: 找出不再使用的变量,然后释放其内存. js中最常用的垃圾收集方法是标记清除,当变量进入环境时,就将变量标记为“进入环境”,当变量离开环境时,将其标记为“离开环境”,最后由垃圾收集器完成 ...

  10. Notes of Daily Scrum Meeting(12.16)

    最近好几门课的大作业都到了要截止的时候了,好多天队员们都抽不出来时间做软工的项目了,这样确实 和我们的计划出入很大,不过希望老师谅解,三门课程设计确实压力很大. 今天的团队任务总结如下: 团队成员 今 ...