【LG3248】[HNOI2016]树
【LG3248】[HNOI2016]树
题面
题解
因为每次你加入的点是原树上某一棵子树
那么我们一次加入一个点,代表一棵子树加到大树下面
那么我们要找到一个点在一个大点中用主席树在\(dfs\)序中\(kth\)即可
询问的话,先将所有的点权(深度)转化为边权
查询时先将两点跳到它所在大点的根
再倍增跳到大点1(原树)的下面,再在原树上倍增跳一跳即可。
虽然说起来容易,但是其实还是很码的qaq。
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
template<typename T>
inline void read(T &data) {
data = 0; T w = 1;
char ch = getchar();
while (ch != '-' && (!isdigit(ch))) ch = getchar();
if (ch == '-') w = -1, ch = getchar();
while (isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
data *= w;
}
typedef long long ll;
const int MAX_N = 1e5 + 5;
int N, M, Q, lg[MAX_N];
namespace Ptree {
struct Node { int ls, rs, v; } t[MAX_N * 20];
int root[MAX_N], tot;
void build(int &o, int l = 1, int r = N) {
o = ++tot;
if (l == r) return ;
int mid = (l + r) >> 1;
build(t[o].ls, l, mid);
build(t[o].rs, mid + 1, r);
}
void insert(int &o, int p, int v, int l = 1, int r = N) {
o = ++tot, t[o] = t[p];
t[o].v++;
if (l == r) return ;
int mid = (l + r) >> 1;
if (v <= mid) insert(t[o].ls, t[p].ls, v, l, mid);
else insert(t[o].rs, t[p].rs, v, mid + 1, r);
}
int query(int x, int y, int k, int l = 1, int r = N) {
if (l == r) return l;
int mid = (l + r) >> 1, s = t[t[y].ls].v - t[t[x].ls].v;
if (k <= s) return query(t[x].ls, t[y].ls, k, l, mid);
else return query(t[x].rs, t[y].rs, k - s, mid + 1, r);
}
}
namespace Template {
int fa[20][MAX_N], dep[MAX_N], pos[MAX_N], R[MAX_N], cnt, L[MAX_N];
struct Graph { int next, to; } e[MAX_N << 1]; int fir[MAX_N], e_cnt;
void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; }
void Add_Edge(int u, int v) { e[e_cnt] = (Graph){fir[u], v}; fir[u] = e_cnt++; }
void dfs(int x, int f) {
L[pos[x] = ++cnt] = x;
fa[0][x] = f;
dep[x] = dep[f] + 1;
for (int i = 1; i < 20; i++) fa[i][x] = fa[i - 1][fa[i - 1][x]];
for (int i = fir[x]; ~i; i = e[i].next) if (e[i].to != f) dfs(e[i].to, x);
R[x] = cnt;
}
int Dis(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
int res = dep[x] - dep[y];
for (int i = 20 - 1; ~i; i--)
if (dep[fa[i][x]] >= dep[y]) x = fa[i][x];
if (x == y) return res;
for (int i = 20 - 1; ~i; i--)
if (fa[i][x] != fa[i][y])
res += 1 << (i + 1), x = fa[i][x], y = fa[i][y];
return res + 2;
}
}
namespace BigTree {
int N, fa[20][MAX_N], dep[MAX_N], pre[MAX_N];
ll dis[20][MAX_N], pos[MAX_N], R[MAX_N], cur, link[MAX_N];
int getRoot(ll x) {
int l = 1, r = N;
while (l <= r) {
int mid = (l + r) >> 1;
if (pos[mid] <= x) l = mid + 1;
else r = mid - 1;
}
return r;
}
int getPre(ll x) {
int rt = getRoot(x);
return Ptree::query(Ptree::root[Template::pos[pre[rt]] - 1], Ptree::root[Template::R[pre[rt]]],
x - pos[rt] + 1);
}
void Init() {
pos[1] = N = dep[1] = pre[1] = 1;
cur = R[1] = ::N;
int x; ll to;
for (int i = 1; i <= M; i++) {
read(x), read(to);
int rt = getRoot(to);
++N, dep[N] = dep[rt] + 1, link[N] = to, pre[N] = x;
pos[N] = cur + 1, R[N] = cur + Template::R[x] - Template::pos[x] + 1;
cur = R[N], fa[0][N] = rt;
dis[0][N] = Template::dep[getPre(to)] - Template::dep[pre[rt]] + 1;
for (int j = 1; j < 20; j++)
fa[j][N] = fa[j - 1][fa[j - 1][N]], dis[j][N] = dis[j - 1][N] + dis[j - 1][fa[j - 1][N]];
}
}
ll Dis(ll x, ll y) {
ll ans = 0;
int fx = getRoot(x), fy = getRoot(y);
if (fx == fy) return Template::Dis(getPre(x), getPre(y));
if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);
ans += Template::dep[getPre(x)] - Template::dep[pre[fx]], x = fx;
for (int i = 20 - 1; ~i; i--)
if (dep[fa[i][x]] > dep[fy]) ans += dis[i][x], x = fa[i][x];
if (getRoot(link[x]) == fy)
return ans + 1 + Template::Dis(getPre(link[x]), getPre(y));
ans += Template::dep[getPre(y)] - Template::dep[pre[fy]], y = fy;
if (dep[x] > dep[y]) ans += dis[0][x], x = fa[0][x];
for (int i = 20 - 1; ~i; i--)
if (fa[i][x] != fa[i][y]) ans += dis[i][x] + dis[i][y], x = fa[i][x], y = fa[i][y];
x = link[x], y = link[y];
ans += 2;
return ans + Template::Dis(getPre(x), getPre(y));
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
read(N), read(M), read(Q);
for (int i = 2; i <= N; i++) lg[i] = lg[i >> 1] + 1;
Template::clearGraph();
for (int i = 1, a, b; i < N; i++)
read(a), read(b), Template::Add_Edge(a, b), Template::Add_Edge(b, a);
Template::dfs(1, 0);
Ptree::build(Ptree::root[0]);
for (int i = 1; i <= N; i++) Ptree::insert(Ptree::root[i], Ptree::root[i - 1], Template::L[i]);
BigTree::Init();
ll x, y;
while (Q--) read(x), read(y), printf("%lld\n", BigTree::Dis(x, y));
return 0;
}
【LG3248】[HNOI2016]树的更多相关文章
- BZOJ 4539: [Hnoi2016]树 [主席树 lca]
4539: [Hnoi2016]树 题意:不想写.复制模板树的子树,查询两点间距离. *** 终于有一道会做的题了...... 画一画发现可以把每次复制的子树看成一个大点来建一棵树,两点的lca一定在 ...
- 4539: [Hnoi2016]树
4539: [Hnoi2016]树 链接 分析: 主席树+倍增. 代码: #include<cstdio> #include<algorithm> #include<cs ...
- [BZOJ4539][HNOI2016]树(主席树)
4539: [Hnoi2016]树 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 746 Solved: 292[Submit][Status][D ...
- [HNOI2016]树(可持久化线段树+树上倍增)
[HNOI2016]树(可持久化线段树+树上倍增) 题面 给出一棵n个点的模板树和大树,根为1,初始的时候大树和模板树相同.接下来操作m次,每次从模板树里取出一棵子树,把它作为新树里节点y的儿子.操作 ...
- BZOJ4539: [Hnoi2016]树
复制的树缩点,主席树查k小,毫无技术含量,纯码农题. #include<bits/stdc++.h> #define u first #define v second #define F ...
- bzoj 4539: [Hnoi2016]树
Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结 点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过 ...
- [HNOI2016]树
Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结 点的编号为1,2,…,N,其中结点1为根:我们称这颗树为模板树.小A决定通过 ...
- 2019.03.25 bzoj4539: [Hnoi2016]树(主席树+倍增)
传送门 题意:给一棵大树,令一棵模板树与这棵树相同,然后进行mmm次操作,每次选择模板树中的一个节点aaa和大树中一个节点bbb,把aaa这棵子树接在bbb上面,节点编号顺序跟aaa中的编号顺序相同. ...
- 洛谷P3248 [HNOI2016]树(主席树 倍增 )
题意 题目链接 Sol 从上午九点淦到现在qwq 思路比较简单,就是把每次加入的一坨点看成一个,然后直接倍增搞.. 然后慢慢调就可以了... 最后数量级会到达\(10^{10}\),所以应该开long ...
随机推荐
- teradata 字符串数据合并 在concat()函数无法使用的情况下
在teradata sql中不存在concat()函数或者stuff()函数,在此情况下,如何实现多条字符串数据合并成一行? 在查找不同方法过程中,在stackflow中找到最简便的方法,使用xml_ ...
- Error loading XML document: dwz.frag.xml 处理方式
问题:直接用IE打开index.html弹出一个对话框:Error loading XML document: dwz.frag.xml 方案一(已经验证): 转自:http://blog.csdn. ...
- 禁用休眠(删除休眠文件) 关掉此选项可节省C盘好几G空间:文章内容bat文件源码
@ECHO offTITLE 关掉休眠 MACHENIKE set TempFile_Name=%SystemRoot%\System32\BatTestUACin_SysRt%Random%.bat ...
- C# Socket编程 笔记,Socket 详解,入门简单
目录 一,网络基础 二,Socket 对象 三,Bind() 绑定与 Connect() 连接 四,Listen() 监听请求连接 和 Accept() 接收连接请求 五,Receive() 与 Se ...
- Spring中手动增加配置文件中占位符引用的变量
在项目中遇到一个这样的需求,项目的配置文件由外部传入,这时spring配置文件那些占位符变量该如何取值呢? 解决这个问题的做法有几种,我想到的大概有以下三种: 1.通过系统属性来实现,把外部传入的配置 ...
- amcharts属性
Amcharts的特点包含: *动画或静态 *价值轴能够扭转 *线性或对数轴的价值尺度 *提前定义或定制的子弹 *定制描写叙述不论什么数据点 *点击栏目/酒吧(可用于钻孔下来图表) *梯度弥漫 *价值 ...
- redis key/value 出现\xAC\xED\x00\x05t\x00\x05
1.问题现象: 最近使用spring-data-redis 和jedis 操作redis时发现存储在redis中的key不是程序中设置的string值,前面还多出了许多类似\xac\xed\x00\x ...
- [AHOI2005]矿藏编码
嘟嘟嘟 这道题题面我是看了小半天才懂(太菜了),然后就发现好水啊. 只要维护一个栈,存的是t,代表当前的正方形是2t * 2t的,然后从头开始扫序列,如果遇到2,就把栈顶元素取出来,然后放进去四个t ...
- PHP MemCached高级缓存配置图文教程
memcache是一个高性能的分布式的内存对象缓存系统,它能够用来存储各种格式的数据,包括图像.视频.文件以及数据库检索的结果等. 1.Memcache相关介绍 memcache是一个高性能的 ...
- 使用阿里云的maven仓库
在maven的settings.xml文件里的mirrors节点,添加如下子节点: <mirror> <id>nexus-aliyun</id> <mirro ...