洛谷P3302 森林
题意:给定森林,可以把两棵树连起来或者询问链上第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 森林的更多相关文章
- 洛谷$P3302$ 森林 $[SDOI2013]$ 主席树
正解:主席树 解题报告: 传送门! 口胡一时爽代码火葬场 这题想法不难,,,但显然的是代码应该还挺难打的 但反正我也不放代码,就写下题解趴$QwQ$ 第一问就是个$Count\ on\ a\ tree ...
- 洛谷 P3302 [SDOI2013]森林 解题报告
P3302 [SDOI2013]森林 题目描述 小\(Z\)有一片森林,含有\(N\)个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有\(M\)条边. 小Z希望执行\(T\)个操作,操 ...
- 洛谷 P3302 [SDOI2013]森林 Lebal:主席树 + 启发式合并 + LCA
题目描述 小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值.初始的时候,森林中有M条边. 小Z希望执行T个操作,操作有两类: Q x y k查询点x到点y路径上所有的权值中,第k小的权 ...
- [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)
传送门 突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288 首先有两个操作,一个查询,一个连接 查询的话,直接 ...
- 洛谷 P3302 [SDOI2013]森林
->题目链接 题解: #include<queue> #include<cstdio> #include<cstring> #include<iostr ...
- 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)
洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不 ...
- 洛谷3月月赛 R1 Step! ZERO to ONE
洛谷3月月赛 R1 Step! ZERO to ONE 普及组难度 290.25/310滚粗 t1 10分的日语翻译题....太难了不会... t2 真·普及组.略 注意长为1的情况 #include ...
- 洛谷P3203 [HNOI2010]弹飞绵羊(LCT,Splay)
洛谷题目传送门 关于LCT的问题详见我的LCT总结 思路分析 首先分析一下题意.对于每个弹力装置,有且仅有一个位置可以弹到.把这样的一种关系可以视作边. 然后,每个装置一定会往后弹,这不就代表不存在环 ...
- 洛谷P4155 [SCOI2015]国旗计划(贪心,树形结构,基数排序)
洛谷题目传送门 \(O(n)\)算法来啦! 复杂度优化的思路是建立在倍增思路的基础上的,看看楼上几位巨佬的描述吧. 首先数组倍长是一样的.倍增法对于快速找到\(j\)满足\(l_j+m\le r_i\ ...
随机推荐
- 20155218《网络对抗》Exp2 后门原理与实践
20155218<网络对抗>Exp2 后门原理与实践 常用后门工具实践 1.Windows获得Linux Shell: 在Windows下,先使用ipconfig指令查看本机IP,使用nc ...
- Luogu P2483 【模板】k短路([SDOI2010]魔法猪学院)
说实话,看到这道题的洛谷评级我傻了(传说中的最高难度) 然后看完题目才确定这真的是一道k短路的裸题. 也就敲了个A*吧,15分钟竟然没有调试一遍过. 欧洲玄学. 看题目,主要是找几条从1走到n的路加起 ...
- 【调试】Core Dump是什么?Linux下如何正确永久开启?
[调试]Core Dump是什么?Linux下如何正确永久开启?
- metasploit-smb扫描获取系统信息
1.msfconsle 2.use auxiliary/scanner/smb/smb_version 3. msf auxiliary(smb_version) > set RHOSTS 17 ...
- .NetCore实践爬虫系统(二)自定义规则
回顾 上篇文章NetCore实践爬虫系统(一)解析网页内容 我们讲了利用HtmlAgilityPack,输入XPath路径,识别网页节点,获取我们需要的内容.评论中也得到了大家的一些支持与建议.下面继 ...
- MQ见解
MQ 消息队列是系统级.模块级的通信.RPC是对象级.函数级通信. 1) 什么是推模式,什么是拉模式 2) 有没有消息丢失情况,如何防止 3) MQ用来解决什么问题 4) 你们用的什么MQ,为什么要用 ...
- linux AB web 性能测试工具
ab(选项)(参数) 选项 -A:指定连接服务器的基本的认证凭据: -c:指定一次向服务器发出请求数: -C:添加cookie: -g:将测试结果输出为“gnuolot”文件: -h:显示帮助信息: ...
- 高精度减法--C++
高精度减法--C++ 仿照竖式减法,先对其,再对应位相减. 算法处理时,先比较大小,用大的减小的,对应位再比较大小,用于作为借位符. #include <iostream> #includ ...
- 机器学习英雄访谈录之 Kaggle Kernels 专家:Aakash Nain
目录 机器学习英雄访谈录之 Kaggle Kernels 专家:Aakash Nain 正文 对我的启发 机器学习英雄访谈录之 Kaggle Kernels 专家:Aakash Nain Sanyam ...
- CentOS7安装OpenStack(Rocky版)-01.控制节点的系统环境准备
分享一下Rocky版本的OpenStack安装管理经验: OpenStack每半年左右更新一版,目前是版本是201808月发布的版本-R版(Rocky),目前版本安装方法优化较好,不过依然是比较复杂 ...