$des$
一棵 $n$ 个点的树,树上有 $m$ 条双向的公交线路,每条公交线路都在
两个节点之间沿最短路径往返。
$q$ 次询问从一个点要到达另一个点,在只坐公交的情况下,至少需
要坐几辆公交车;或者判断无法只坐公交到达。
$n,m,q <= 2 \times 10^5$

$sol$
对于每个点,先预处理出从这个点坐一次公交车能最远到达哪个
祖先。对于一条公交线路 (u,v),将 lca 的信息挂在 u,v 上,dfs 一遍向上
更新信息即可。
通过倍增算出从某个点坐 $2^k$ 次最远能到达哪个祖先。这样对于一
条路径 (u,v),我们就能快速算出 u,v 走到 lca 分别至少需要多少辆车,
假设答案分别为 $a,b$,那么询问的答案要么是 $a + b$,要么是 $a + b - 1$

。判断的方法也很简单,先算出 $u$ 向上坐 $a - 1$ 次,$v$ 向上坐 $b - 1$

次,最远能到达哪个节点。若存在一条线路经过这两个节点,则答案
为 $a + b - 1$。也就是判断是否有一条线路的两端分别在这两个节点的
子树中。
这可以变成了一个二维数点问题,时间复杂度 $O((n + m + q)logn)$,不会

$O(nlog^2n)$ 卡过
问题转化为树上存在 $n$ 对点对,每对点对带有不同的权值 a,每次询问点对

$(x, y)$ 二者的子树内是否存在相同的点的权值
可以用线段树套set维护

$code$

#include <bits/stdc++.h>

using namespace std;

#define gc getchar()
inline int read() {
int x = ; char c = gc;
while(c < '' || c > '') c = gc;
while(c >= '' && c <= '') x = x * + c - '', c = gc;
return x;
} #define E exit(0)
#define Rep(i, a, b) for(int i = a; i <= b; i ++) const int N = 2e5 + ; int fa[N], size[N], topp[N], son[N], deep[N] = {( << )}, lst[N], rst[N], sptime;
int f[N][];
int upst[N]; vector <int> G[N]; int n; void Dfs_1(int u, int f_, int dep) {
fa[u] = f_, deep[u] = dep, size[u] = ;
int S = G[u].size();
Rep(i, , S - ) {
int v = G[u][i];
if(v == f_) continue;
Dfs_1(v, u, dep + );
if(size[v] > size[son[u]]) son[u] = v;
}
} void Dfs_2(int u, int tp) {
topp[u] = tp; lst[u] = ++ sptime;
if(!son[u]) {
rst[u] = sptime; return ;
}
Dfs_2(son[u], tp);
int S = G[u].size();
Rep(i, , S - ) {
int v = G[u][i];
if(v != fa[u] && v != son[u]) Dfs_2(v, v);
}
rst[u] = sptime;
} inline int Lca(int x, int y) {
int tpx = topp[x], tpy = topp[y];
while(tpx != tpy) {
if(deep[tpx] < deep[tpy]) swap(x, y), swap(tpx, tpy);
x = fa[tpx], tpx = topp[x];
}
if(x == y) return x;
if(deep[x] < deep[y]) swap(x, y);
return y;
} void Dfs_3(int u) {
int S = G[u].size();
Rep(i, , S - ) {
int v = G[u][i];
if(v == fa[u]) continue;
Dfs_3(v);
if(deep[upst[v]] < deep[upst[u]]) upst[u] = upst[v];
}
} set <int> Tree[N << ]; #define lson jd << 1
#define rson jd << 1 | 1 void Poi_G(int l, int r, int jd, int x, int num) {
if(Tree[jd].count(num) == ) Tree[jd].insert(num);
if(l == r) return ;
int mid = (l + r) >> ;
if(x <= mid) Poi_G(l, mid, lson, x, num);
else Poi_G(mid + , r, rson, x, num);
} bool flag; set <int> :: iterator wl, wr; void Sec_A(int l, int r, int jd, int x, int y, int fl, int fr) {
if(flag || Tree[jd].size() == ) return ;
if(x <= l && r <= y) {
if(Tree[jd].count(fl) || Tree[jd].count(fr)) {
flag = ; return ;
}
Tree[jd].insert(fr);
wl = Tree[jd].lower_bound(fl);
wr = Tree[jd].lower_bound(fr);
Tree[jd].erase(fr);
if(wr == wl) return ;
if(wr != wl) flag = ;
return ;
}
int mid = (l + r) >> ;
if(x <= mid && flag == ) Sec_A(l, mid, lson, x, y, fl, fr);
if(y > mid && flag == ) Sec_A(mid + , r, rson, x, y, fl, fr);
} inline void Calc(int x, int y) {
int ret;
int lca = Lca(x, y);
int a = , b = , lstx = x, lsty = y, tmpx = x, tmpy = y;
for(int i = ; i >= ; i --) {
if(deep[f[x][i]] > deep[lca]) a += ( << i), x = f[x][i];
}
for(int i = ; i >= ; i --) {
if(deep[f[y][i]] > deep[lca]) b += ( << i), y = f[y][i];
}
if(deep[f[x][]] > deep[lca] || deep[f[y][]] > deep[lca]) {
puts("-1"); return ;
}
flag = ;
int l1 = lst[x], r1 = rst[x], l2 = lst[y], r2 = rst[y];
Sec_A(, n, , l1, r1, l2, r2); Sec_A(, n, , l2, r2, l1, r1);
if(lca == x || lca == y) ret = a + b + ;
else if(flag == ) ret = a + b + ;
else ret = a + b + ;
printf("%d\n", ret);
} int main() {
n = read(); Rep(i, , n) {
int u = read();
G[u].push_back(i), G[i].push_back(u);
} Dfs_1(, , );
Dfs_2(, ); int m = read();
Rep(i, , m) {
int u = read(), v = read();
int lca = Lca(u, v);
if(deep[lca] < deep[upst[u]] || upst[u] == ) upst[u] = lca;
if(deep[lca] < deep[upst[v]] || upst[v] == ) upst[v] = lca;
Poi_G(, n, , lst[u], lst[v]);
} Dfs_3();
Rep(i, , n) f[i][] = upst[i];
Rep(i, , ) {
Rep(j, , n) f[j][i] = f[f[j][i - ]][i - ];
} m = read();
Rep(i, , m) {
int a = read(), b = read();
Calc(a, b);
}
return ;
}

97: cf 983E 倍增+树套树的更多相关文章

  1. BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Sta ...

  2. BZOJ4170 极光(CDQ分治 或 树套树)

    传送门 BZOJ上的题目没有题面-- [样例输入] 3 5 2 4 3 Query 2 2 Modify 1 3 Query 2 2 Modify 1 2 Query 1 1 [样例输出] 2 3 3 ...

  3. bzoj3262: 陌上花开(树套树)

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  4. bzoj3295: [Cqoi2011]动态逆序对(树套树)

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  5. BZOJ 3110 k大数查询 & 树套树

    题意: 有n个位置,每个位置可以看做一个集合,现在要求你实现一个数据结构支持以下功能: 1:在a-b的集合中插入一个数 2:询问a-b集合中所有元素的第k大. SOL: 调得火大! 李建说数据结构题能 ...

  6. BZOJ 3110 树套树 && 永久化标记

    感觉树套树是个非常高深的数据结构.从来没写过 #include <iostream> #include <cstdio> #include <algorithm> ...

  7. 【BZOJ】1901: Zju2112 Dynamic Rankings(区间第k小+树套树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1901 这题调了我相当长的时间,1wa1a,我是第一次写树套树,这个是树状数组套splay,在每个区间 ...

  8. hdu 4417 Super Mario/树套树

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 题意很简单,给定一个序列求一个区间 [L, R,]中小于等于H的元素的个数. 好像函数式线段树可 ...

  9. Uva 3767 Dynamic len(set(a[L:R])) 树套树

    Dynamic len(set(a[L:R])) Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 https://uva.onlinejudge.org/in ...

随机推荐

  1. Go语言变量的初始化

    正如上一节<Go语言变量声明>中提到的 Go语言在声明变量时,自动对变量对应的内存区域进行初始化操作.每个变量会初始化其类型的默认值,例如: 整型和浮点型变量的默认值为 0. 字符串变量的 ...

  2. Jupyter交互式工具安装使用

    Jupyter交互式工具安装使用 Jupyter Notebook(此前被称为IPython notebook)是一个交互式笔记本,支持运行 40 多种编程语言. 文档:https://jupyter ...

  3. SQL Server 截取日期部分字符

    select GetDate() --用DateName()就可以获得相应的年.月.日 Select Datename(year,GetDate())+'-'+Datename (month,GetD ...

  4. 隐马尔可夫模型(HMM)的分类

    1.遍历型(ergodic model) 即每个状态都可以由任意一个状态演变而来,aij>0,for all i , j. 如图: 2.left-right type of HMM 每个状态只能 ...

  5. 1-redis使用笔记

    1.清空当前redis数据库缓存FLUSHDB flushdb 2.清空整个redis缓存FLUSHALL flushall 3.设置 SET w3ckey redis 4.获取 GET w3ckey ...

  6. springboot笔记07——整合MyBatis

    前言 Springboot 整合 MyBatis 有两种方式,分别是:"全注解版" 和 "注解.xml混合版". 创建项目 创建Springboot项目,选择依 ...

  7. Oracle 11g 服务器结构

    Oracle 服务器主要又实例.数据库.程序全局区和前台进程组成. 实例可以进一步划分为系统全局区(SGA)和后台进程(PMON.SMON等)两部分,其中,SGA 使用操作系统的内存资源,而后台进程需 ...

  8. Windows环境下大数据处理的构想(一)

    为什么不呢?我们有了RPC/RMI和MAP,为什么不能在windows环境下处理大数据呢?windows是迄今为止最普及的操作系统,据市调公司NetMarketShare最新(2019年5月)统计数据 ...

  9. Python itchat模块的使用,利用图灵机器人进行微信消息自动回复

    一.下载安装itchat模块 二.小实验:获取微信好友头像信息 这需要用itchat模块中的一个方法 itchat.get_friends()#获取微信所有微信好友信息 现在我们导入itchat,打印 ...

  10. 请解释下在单线程模型中Message、Handler、MessageQueue、Looper之间的关系

    对于面试,每个职场人士都经历过,面试官更看中你对于技术的理解是否透彻,需要知其所以然,而实际工作中看中的工作效率,都是在使用API的角度来完成任务,当在一家公司呆久了有跳槽的想法时,个人的亲身经历就是 ...