题意:给定森林,可以把两棵树连起来或者询问链上第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. Luogo P2324 [SCOI2005]骑士精神

    所有想练习A*的人都先来敲一下这道题吧. 数据范围即便只有5*5,但朴素的爆搜还是会超时. 因此考虑剪枝. 对于这道题,肯定只要进行最优化剪枝,判断现在走的步数+剩下最少要走的步数,如果大于ans或者 ...

  2. 手把手教你搭APM之Skywalking搭建指南(支持Java/C#/Node.js)

    前言 什么是APM?全称:Application Performance Management 可以参考这里: 现代APM体系,基本都是参考Google的Dapper(大规模分布式系统的跟踪系统)的体 ...

  3. datatables.js 简单使用--弹出编辑框或添加数据框

    内容:选中某一条记录,弹出编辑框 环境:asp.net mvc ,  bootstrap 显示效果: 代码: 至于怎么弄多选框,在上一篇博客里已经有说明. 主要用到了bootstrap的模态窗,下面代 ...

  4. MIT-6.824 MapReduce

    概述 MapReduce是由JeffreyDean提出的一种处理大数据的编程模型,用户定义map和reduce函数,map函数处理原始数据生成一系列键值对中间数据,reduce函数并合相同key的键值 ...

  5. 微软职位内部推荐-Software Development Engineer II_Commerce

    微软近期Open的职位: Are you looking for a high impact project that involves processing of billions of dolla ...

  6. PHP Laravel Install and Quickstart

    1.安装Laravel 一键安装包Laravel 要安装Laravel依赖的PHP7以上版本,以及php 扩展php-openssl php-pdo ... 以及Homestead github下载安 ...

  7. springmvc 事务回滚说明

    Spring中的@Transactional(rollbackFor = Exception.class)属性详解 序言 今天我在写代码的时候,看到了.一个注解@Transactional(rollb ...

  8. Daily Scrum NO.8

    工作概况 今天是周六,虽然由于工作紧张要求这一日也定为工作日,但是也许是因为昨日大家工作做得较多或者周末的缘故,今天的进展状况并不理想.线程池和异常清理器的后端已经完成,而清理器的界面和动态爬取仍旧没 ...

  9. 《Linux内核设计与实现》第5章读书整理

                                 <第五章 系统调用>笔记 5.1 与内核通信 系统调用在用户空间和硬件设备之间提供了一个中间层. 中间层的作用: 为用户空间提供一 ...

  10. 调研ios开发环境的演变

    一:ios的发展演变: 以下两句为百度百科IOS,可自行查阅,不多赘述,就Ctrl+c,Ctrl+v两句表示一下. 2007年1月9日苹果公司在Macworld展览会上公布,随后于同年的6月发布第一版 ...