【xsy1156】 树套树(tree) 倍增
题目大意:给你$m$棵由$n$个点构成的全等的树$A$。这$m$棵树之间有$m-1$条边相连,组成了一棵大树。
有$q$组询问,每次询问这棵大树上两点之间的距离。
$n,m,q≤10^5$
这是一道小视野双倍经验题
这一题有一种显然的虚树做法,这种做法我之前打过了,这次换一种做法。
如果询问所在两点在同一棵小树内,那么显然直接倍增就可以了。
我们将连接$m$棵树的边抽出来,构成另外一棵树(暂且称作树$B$),节点$p$表示第$p$棵树,我们钦定这棵树的$1$号点为根。
我们令$up1[i]$表示树$B$中,连接$i$号点$father$所在的边,它在第$i$棵小树中所连接的节点。
令$up2[i]$表示树$B$中,连接$i$号点$father$所在的边,它在第$fa[i]$棵小树中所连接的点。
令$dis[i]$表示从树$B$的第$1$号树的$1$号节点开始,到达小树$i$第$up1[i]$号节点的距离。
对于一组询问$(w,x,y,z)$,我们求出$w,y$的$lca$,令$w'$表示在$w$到$lca$的路径上,离$lca$最近的点(不包括$lca$本身),同理求出$y'$。
设最终答案为$ans$
若存在$w'$,则$ans+=A.dis(x,up1[x])+dis[w]-dis[w']$,并令$x=up2[w']$。
若存在$y'$,则$ans+=A.dis(z,up1[z])+dis[y]-dis[y']$,并令$z=up2[y']$。
最后$ans+=A.dis(x,z)$即可。
注意细节
#include<bits/stdc++.h>
#define M 100005
#define L long long
using namespace std;
int n,m,q;
struct tree1{
struct edge{int u,next;}e[M*]; int head[M],use=;
void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
int f[M][],dep[M];
void dfs(int x,int fa){
f[x][]=fa; dep[x]=dep[fa]+;
for(int i=;i<;i++) f[x][i]=f[f[x][i-]][i-];
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa) dfs(e[i].u,x);
}
int getlca(int x,int y){
if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y];
for(int i=;~i;i--) if((<<i)&cha) x=f[x][i];
for(int i=;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
if(x==y) return x; return f[x][];
}
int getdis(int x,int y){
int lca=getlca(x,y);
return dep[x]+dep[y]-*dep[lca];
}
void init(){
for(int i=;i<n;i++){
int x,y; scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(,);
}
}a;
struct tree2{
struct edge{int u,us,ut,next;}e[M*]; int head[M],use=;
void add(int x,int y,int us,int ut){use++;e[use].u=y;e[use].us=us;e[use].ut=ut;e[use].next=head[x];head[x]=use;}
int f[M][],dep[M],up1[M],up2[M]; L dis[M];
void dfs(int x,int fa){
f[x][]=fa; dep[x]=dep[fa]+;
for(int i=;i<;i++) f[x][i]=f[f[x][i-]][i-];
for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
up1[e[i].u]=e[i].ut; up2[e[i].u]=e[i].us;
dis[e[i].u]=dis[x]+a.getdis(up1[x],e[i].us)+;
dfs(e[i].u,x);
}
}
int getlca(int x,int y){
if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y];
for(int i=;~i;i--) if((<<i)&cha) x=f[x][i];
for(int i=;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
if(x==y) return x; return f[x][];
}
int jump(int x,int k){
for(int i=;~i;i--) if((<<i)&k) x=f[x][i];
return x;
}
void init(){
for(int i=;i<m;i++){
int x,X,y,Y; scanf("%d%d%d%d",&x,&X,&y,&Y);
add(x,y,X,Y); add(y,x,Y,X);
}
dfs(,);
}
}b;
int main(){
scanf("%d%d%d",&n,&m,&q);
a.init();
b.init();
while(q--){
int x,X,y,Y; scanf("%d%d%d%d",&x,&X,&y,&Y);
int lca=b.getlca(x,y);
L ans=;
if(x!=lca){
ans+=a.getdis(X,b.up1[x]);
int xx=b.jump(x,b.dep[x]-b.dep[lca]-);
ans+=b.dis[x]-b.dis[xx]+;
X=b.up2[xx];
}
if(y!=lca){
ans+=a.getdis(Y,b.up1[y]);
int yy=b.jump(y,b.dep[y]-b.dep[lca]-);
ans+=b.dis[y]-b.dis[yy]+;
Y=b.up2[yy];
}
ans+=a.getdis(X,Y);
printf("%lld\n",ans);
}
}
【xsy1156】 树套树(tree) 倍增的更多相关文章
- bzoj3262: 陌上花开(树套树)
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...
- 树套树专题——bzoj 3110: [Zjoi2013] K大数查询 & 3236 [Ahoi2013] 作业 题解
[原题1] 3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 978 Solved: 476 Descri ...
- BZOJ_3196_二逼平衡树_(树套树,线段树+Treap)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3196 可以处理区间问题的平衡树. 3196: Tyvj 1730 二逼平衡树 Time Lim ...
- bzoj 3295: [Cqoi2011]动态逆序对(树套树 or CDQ分治)
Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计 ...
- BZOJ3110 [Zjoi2013]K大数查询 树套树 线段树 整体二分 树状数组
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3110 题意概括 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位 ...
- 【bzoj1901】dynamic ranking(带修改主席树/树套树)
题面地址(权限题) 不用权限题的地址 首先说说怎么搞带修改主席树? 回忆一般的kth问题,我们的主席树求的是前缀和,这样我们在目标区间的左右端点的主席树差分下就能求出kth. 那么我们如何支持修改操作 ...
- Dynamic Rankings(动态第k大+树套树)
题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112 题目: 思路: 树套树板子题. 代码实现如下: #inclu ...
- Educational Codeforces Round 56 (Rated for Div. 2) E(1093E) Intersection of Permutations (树套树,pb_ds)
题意和分析在之前的链接中有:https://www.cnblogs.com/pkgunboat/p/10160741.html 之前补题用三维偏序的cdq的分治A了这道题,但是感觉就算比赛再次遇到类似 ...
- 树套树Day2
滚回来更新,,, 在Day1我们学了最基本的线段树套平衡树 Day2开始我们要学习一些黑科技 (所以很大概率会出现Day3 w 1.线段树上的黑科技 这一段我们分几项来讲 1.权值线段树 权值线段树以 ...
- 树套树Day1线段树套平衡树bzoj3196
您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查 ...
随机推荐
- Check time of different search methods
https://github.com/Premiumlab/Python-for-Algorithms--Data-Structures--and-Interviews/blob/master/Moc ...
- HTML5/CSS3基础
1. HTML 1.1 什么是HTML HTML是用来制作网页的标记语言 HTML是Hypertext Markup Language的英文缩写,即超文本标记语言 HTML语言是一种标记语言,不需要编 ...
- 2018.07.30 cogs2632. [HZOI 2016] 数列操作d(线段树)
传送门 线段树基本操作 区间加等差数列,维护区间和. 对于每个区间维护等差数列首项和公差,易证这两个东西都是可合并的,然后使用小学奥数的知识就可以切掉这题. 代码: #include<bits/ ...
- 浅析基于AXIS框架的WebService
一.写在前面 之前做项目用到了基于Axis的WebService,为了更进一步的理解和记忆,在这里通过代码实践和源码分析来完整的做一遍Axis的WebService以及对应的客户端调用实践,并和其它的 ...
- Sql Server R8 密码问题及5102错误
登录的两种方式: 集成登录连接:con = new SqlConnection("server=.\\SQLEXPRESS;database=db_news;Trusted_Connecti ...
- accumarray
Example Create a -by- vector and sum values -D subscripts: val = :; subs = [; ; ; ; ] subs = A = acc ...
- TFS 如何強制撤銷被簽出的文件
我们在使用TFS (Team Foundation Server) 源代码管理的时候,源代码管理会在每个PC上创建一个工作区,然后这个工作区域映像到服务器上的源码文件夹,我们在正常签入,签出的时候,我 ...
- ActiveMq 总结(一)
1. 背景 当前,CORBA.DCOM.RMI等RPC中间件技术已广泛应用于各个领域.但是面对规模和复杂度都越来越高的分布式系统,这些技术也显示出其局限性:(1)同步通信:客户发出调用后,必须等待服务 ...
- 使用sos查看.NET对象内存布局
前面我们图解了.NET里各种对象的内存布局,我们再来从调试器和clr源码的角度来看一下对象的内存布局.我写了一个测试程序来加深对.net对象内存布局的了解: using System; using S ...
- ASP.NET在请求中检测到包含潜在危险的数据,因为它可能包括 HTML标记或脚本
背景:程序迁移到新的服务器上,在程序进行修改操作时,提示包含危险数据.然而在旧服务器上却没有问题,我猜想的可能是,新服务器IIS安装的ASP.NET版本框架高于以前的IIS上的版本框架,导致web.c ...