[HNOI 2016]树
Description
给你一棵 \(N\) 个节点根节点为 \(1\) 的有根树,结点的编号为 \(1\sim N\) ;我们称这颗树为模板树。需要通过这棵模板树来构建一颗大树。构建过程如下:
- 将模板树复制为初始的大树;
- 以下 2.1 2.2 2.3 步循环执行 \(M\) 次:
2.1. 选择两个数字 \(a,b\) ,其中 \(1\leq a\leq N,1\leq b\leq 当前大树的结点数\) ;
2.2. 将模板树中以结点 \(a\) 为根的子树复制一遍,挂到大树中结点 \(b\) 的下方(也就是说,模板树中的结点 \(a\) 为根的子树复制到大树中后,将成为大树中结点 \(b\) 的子树);
2.3. 将新加入大树的结点按照在模板树中编号的顺序重新编号。大树中这 \(C\) 个结点编号的大小顺序和模板树中对应的 \(C\) 个结点的大小顺序是一致的。
操作结束后 \(Q\) 组询问,询问两点间的距离。
\(1\leq N,M,Q\leq 100000\)
Solution
感觉是 \(HNOI~2016\) 最简单的题...
首先发现最坏的情况下有 \(N\times M\) 个节点;显然不能一个一个节点存下;
容易想到的就是把每一次操作截下来的子树缩成一个点。我们可以再建一个图来维护操作新建的节点间的关系;
其次对于节点的编号;其实就是转化成求子树点权的 \(K\) 大;用 \(dfs\) 序,将这个问题变成序列求区间 \(K\) 大。因为同一个子树中的节点的 \(dfs\) 序是相邻的。用主席树解决。
然后就是疯狂套模版+询问讨论就好了。鬼知道哪些要开 \(long~long\) ,就全开了。
Code
//It is made by Awson on 2018.3.5
#include <bits/stdc++.h>
#define LL long long
#define dob complex<double>
#define Abs(a) ((a) < 0 ? (-(a)) : (a))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
#define writeln(x) (write(x), putchar('\n'))
#define lowbit(x) ((x)&(-(x)))
using namespace std;
const LL N = 100000;
void read(LL &x) {
char ch; bool flag = 0;
for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
x *= 1-2*flag;
}
void print(LL x) {if (x > 9) print(x/10); putchar(x%10+48); }
void write(LL x) {if (x < 0) putchar('-'); print(Abs(x)); }
LL n, m, q, u, v, lim, size[N+5], opt[N+5][3], sum[N+5], id[N+5], loc;
struct Segment_tree {
LL root[N+5], ch[N*50+5][2], key[N*50+5], pos;
LL cpynode(LL o) {++pos; ch[pos][0] = ch[o][0], ch[pos][1] = ch[o][1], key[pos] = key[o]; return pos; }
void insert(LL &o, LL l, LL r, LL loc) {
o = cpynode(o); ++key[o];
if (l == r) return; LL mid = (l+r)>>1;
if (loc <= mid) insert(ch[o][0], l, mid, loc); else insert(ch[o][1], mid+1, r, loc);
}
LL query(LL a, LL b, LL l, LL r, LL k) {
if (l == r) return l; LL mid = (l+r)>>1;
LL tmp = key[ch[b][0]]-key[ch[a][0]];
if (tmp >= k) return query(ch[a][0], ch[b][0], l, mid, k);
else return query(ch[a][1], ch[b][1], mid+1, r, k-tmp);
}
}T;
struct graph {
struct tt {LL to, next, cost; }edge[(N<<1)+5];
LL path[N+5], top, fa[N+5][20], dep[N+5], dist[N+5];
void add(LL u, LL v, LL c = 1) {edge[++top].to = v, edge[top].cost = c, edge[top].next = path[u], path[u] = top; }
void dfs(LL o, LL father, LL depth, LL dst) {
fa[o][0] = father, dep[o] = depth, dist[o] = dst; for (LL i = 1; i <= lim; i++) fa[o][i] = fa[fa[o][i-1]][i-1];
for (LL i = path[o]; i; i = edge[i].next)
if (edge[i].to != father) dfs(edge[i].to, o, depth+1, dst+edge[i].cost);
}
LL lca(LL u, LL v) {
if (dep[u] < dep[v]) Swap(u, v);
for (LL i = lim; i >= 0; i--) if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
if (u == v) return u;
for (LL i = lim; i >= 0; i--) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
LL slca(LL u, LL lca) {for (LL i = lim; i >= 0; i--) if (dep[fa[u][i]] > dep[lca]) u = fa[u][i]; return u; }
LL dis(LL u, LL v) {return dist[u]+dist[v]-(dist[lca(u, v)]<<1); }
void btree(LL o) {
id[o] = ++loc;
T.root[loc] = T.root[loc-1]; T.insert(T.root[loc], 1, n, o); size[o] = 1;
for (LL i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa[o][0]) btree(edge[i].to), size[o] += size[edge[i].to];
}
}g1, g2;
LL ids(LL u, LL v) {return T.query(T.root[id[opt[u][0]]-1], T.root[id[opt[u][0]]+size[opt[u][0]]-1], 1, n, v-sum[u-1]); }
LL query(LL a, LL b, LL u, LL v) {
LL ans = 0, lca = g2.lca(a, b);
if (a != lca) {
ans += g1.dis(u, opt[a][0])+1;
LL t = g2.slca(a, lca); ans += g2.dis(a, t);
u = ids(lca, opt[t][2]);
}
if (b != lca) {
ans += g1.dis(v, opt[b][0])+1;
LL t = g2.slca(b, lca); ans += g2.dis(b, t);
v = ids(lca, opt[t][2]);
}
return ans+g1.dis(u, v);
}
void work() {
read(n), read(m), read(q), ++m; lim = log(n)/log(2);
for (LL i = 1; i < n; i++) read(u), read(v), g1.add(u, v), g1.add(v, u);
g1.dfs(1, 0, 1, 0); g1.btree(1); opt[1][0] = 1; opt[1][1] = sum[1] = n;
for (LL i = 2; i <= m; i++) {
read(opt[i][0]), read(v); opt[i][2] = v; u = lower_bound(sum+1, sum+i, v)-sum;
LL a = ids(u, v);
g2.add(u, i, g1.dis(opt[u][0], a)+1);
opt[i][1] = size[opt[i][0]], sum[i] = sum[i-1]+opt[i][1];
}
g2.dfs(1, 0, 1, 0);
while (q--) {
read(u), read(v);
LL a = lower_bound(sum+1, sum+m+1, u)-sum, b = lower_bound(sum+1, sum+m+1, v)-sum;
writeln(query(a, b, ids(a, u), ids(b, v)));
}
}
int main() {
work(); return 0;
}
[HNOI 2016]树的更多相关文章
- 【BZOJ 4539】【HNOI 2016】树
http://www.lydsy.com/JudgeOnline/problem.php?id=4539 今天测试唯一会做的一道题. 按题目要求,如果暴力的把模板树往大树上仍,最后得到的大树是$O(n ...
- 数据结构(树链剖分,堆):HNOI 2016 network
2215. [HNOI2016]网络 ★★★☆ 输入文件:network_tenderRun.in 输出文件:network_tenderRun.out 简单对比时间限制:2 s 内存 ...
- HNOI 2016 省队集训日记
第一天 DeepDarkFantasy 从东京出发,不久便到一处驿站,写道:日暮里. ——鲁迅<藤野先生> 定义一个置换的平方为对1~n的序列做两次该置换得到的序列.已知一个置换的平方, ...
- [HNOI 2004]树的计数
Description 一个有n个结点的树,设它的结点分别为v1, v2, …, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, …, dn,编程需要 ...
- [HNOI 2016]网络
Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...
- 【HNOI 2016】网络
Problem Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器 ...
- HNOI 2016 地图
[题目描述] Hoshizora Rin是个特别好动的少女. 一天Rin来到了一个遥远的都市.这个都市有N个建筑,编号从1到N,其中市中心编号为1,这个都市有M条双向通行的街道,每条街道连接着两个建筑 ...
- [ HEOI 2016 ] 树
\(\\\) Description 给出一颗树,开始只有 \(1\) 号节点有标记. \(\ C\ x\) 对 \(x\) 号节点打标记 \(\ Q\ x\) 查询 \(x\) 号节点深度最深的有标 ...
- COGS 2532. [HZOI 2016]树之美 树形dp
可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...
随机推荐
- 2017-2018-1 Java演绎法 第三周 作业
团队任务:团队展示与选题 团队展示 队员学号及姓名 学号 姓名 主要负责工作 20162315 马军 日常统计,项目部分代码 20162316 刘诚昊 项目部分代码,代码质量测试 20162317 袁 ...
- C语言--总结报告
1.当初你是如何做出选择计算机专业的决定的? 经过一个学期,你的看法改变了么,为什么? 你觉得计算机是你喜欢的领域吗,它是你擅长的领域吗? 为什么? 当初填报志愿我是有很明确的专业方向的,就是IT类的 ...
- Beta敏捷冲刺每日报告——Day3
1.情况简述 Beta阶段Scrum Meeting 敏捷开发起止时间 2017.11.4 00:00 -- 2017.11.5 00:00 讨论时间地点 2017.11.4 晚9:30,电话会议会议 ...
- JavaScript简写技巧总结
在日常工作中,JavaScript一些常用的简写技巧,将直接影响到我们的开发效率,现将常用技巧整理如下: 1. 空(null, undefined)验证 当我们创建了一个新的变量,我们通常会去 ...
- Vue filter介绍及详细使用
Vue filter介绍及其使用 VueJs 提供了强大的过滤器API,能够对数据进行各种过滤处理,返回需要的结果. Vue.js自带了一些默认过滤器例如: capitalize 首字母大写 uppe ...
- 部分和问题 nyoj
部分和问题 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 给定整数a1.a2........an,判断是否可以从中选出若干数,使它们的和恰好为K. 输入 首先, ...
- HTML 样式设计
1.自动设置外边距 style="margin:auto auto;"
- JAVA_SE基础——55.自定义异常类
在Java中已经提供了大量的异常类,但是这些异常类有时野很难满足开发者的要求,所以用户可以根据自己的需要来定义自己的异常类.但自定义的异常类必须继承自Exception或其子类. 可以自定义出的问题称 ...
- awk sed tr替换换行符为逗号,并合并为一行
在群里看到的.记录以备用. sed 帮助命令:http://man.linuxde.net/sed 文件里有如下行,我想将每行的回车符替换为逗号,并将所有行合并到一行,用awk或sed怎么写啊TOP ...
- 判断一个字符串是不是一个合法的IP地址
最近在笔试的时候遇到碰一道算法题, 要求判断一个字符串是不是合法的ip地址. 将我的思路发出来分享一下,不一定正确,也不一定是最优的方法.希望能分享一些交流 要求用java或者c来实现,我的java代 ...