题意:给定森林,可以把两棵树连起来或者询问链上第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. 20155232《网络对抗》Exp3 免杀原理与实践

    20155232<网络对抗>Exp3 免杀原理与实践 问题回答 1.基础问题回答 (1)杀软是如何检测出恶意代码的? 基于特征码的检测 特征码:一段特征码就是一段或多段数据. 如果一个可执 ...

  2. 基于Boost库的HTTP Post函数

    两个函数的区别: 提交表单数据和提交文本数据 表单数据: request_stream << "Content-Type: application/x-www-form-urle ...

  3. linux 定时器原理

    内核定时器:    unsigned long timeout = jiffies + (x * HZ);    while(1) {        // Check the condition.   ...

  4. vs编译器好多下划波浪线但不报错

    解决办法:项目属性->c/c++->常规->附加包含目录->$(ProjectDir): $(ProjectDir) 项目的目录(定义形式:驱动器 + 路径):包括尾部的反斜杠 ...

  5. PowerBI开发 第六章:数据网管

    Power BI的本地数据网管(On-Premises Data Gateway)是运行在组织内部的软件,用于管控外部用户访问内部(on-premises)数据的权限.PowerBI的网管像是一个尽职 ...

  6. 利用privoxy劫持http网站数据,插入广告,获取用户名,密码

    看了几篇privoxy的文章,感觉讲的都不详细,在此整理一遍. 注:本文下面的内容仅讨论思路,作为技术交流之用,请勿用作非法途径. Privoxy是一款带过滤功能的代理服务器,针对HTTP.HTTPS ...

  7. 【ORACLE】Win2008R2修改oracle数据库实例名

    需求说明:要求将windows平台的数据库实例名由orcl改为haha 参考: https://www.cnblogs.com/junnor/archive/2013/03/05/2945245.ht ...

  8. Kubernetes并发控制与数据一致性的实现原理

    在大型分布式系统中,定会存在大量并发写入的场景.在这种场景下如何进行更好的并发控制,即在多个任务同时存取数据时保证数据的一致性,成为分布式系统必须解决的问题.悲观并发控制和乐观并发控制是并发控制中采用 ...

  9. A1043 Is It a Binary Search Tree (25 分)

    A Binary Search Tree (BST) is recursively defined as a binary tree which has the following propertie ...

  10. 转载:ArcEngine 唯一值查询

    转载 http://virgoooos.iteye.com/blog/512329 转载:http://blog.csdn.net/mydriverc/archive/2007/07/26/17092 ...