SPOJ375 Query on a tree 【倍增,在线】
题目链接【http://www.spoj.com/problems/QTREE/】
题意:给出一个包含N(N<=10000)节点的无根树,有多次询问,询问的方式有两种1、DIST a b 求a->b之间的距离。2、KTH a b k 求a->b链上的第k个节点是谁,。如果输入DONE,结束询问。
思路:首先想到用倍增法可以解决第一种询问,只需要在DFS时候维护一个dis[i](表示i节点到根节点之间的距离,因为是无根树,我们定义节点1为根),dis(a->b)=dis[a]+dis[b]-dia[lca(a,b)]。第二种询问的解法是首先求出a,b的lca,然后根据lca到a到b的深度判断第k个数在左半枝还是右半枝(可以定义lca为左半枝),然后用倍增的方法求出第k个节点。
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = ;
struct node
{
int id, len, next;
} E[maxn << ];
int p[maxn << ], num;
void init()
{
memset(p, -, sizeof(p));
num = ;
}
void add(int u, int v, int dis)
{
E[num].id = u;
E[num].len = dis;
E[num].next = p[v];
p[v] = num++;
}
//------------------------------------------邻接表
int T, N;
int fa[][maxn];//倍增数组
int dis[maxn], dep[maxn];//距离,深度数组
void DFS(int u, int FA)//DFS求出每个节点的深度,每个节点到根节点的距离,和每个节点跳1步到达的位置
{
for(int l = p[u]; l != -; l = E[l].next)
{
int id = E[l].id;
if(id == FA) continue;
fa[][id] = u;
dep[id] = dep[u] + ;
dis[id] = dis[u] + E[l].len;
DFS(id, u);
}
}
void INIT()//初始化倍增数组
{
memset(fa, -, sizeof(fa));
memset(dis, , sizeof(dis));
memset(dep, , sizeof(dep));
DFS(, -);
for(int k = ; k + <= ; k++)
{
for(int u = ; u <= N; u++)
{
if(fa[k][u] < )
fa[k + ][u] = -;
else
fa[k + ][u] = fa[k][fa[k][u]];
}
}
}
int LCA(int u, int v)
{
if(dep[u] > dep[v]) swap(u, v);
for(int k = ; k <= ; k++)//微调,使得dep相等
if((dep[v] - dep[u]) >> k & )
v = fa[k][v];
if(u == v) return u;//公共祖先是u,v中的其中一个
for(int k = ; k >= ; k--)//一起向上跳,先跳距离远的
{
if(fa[k][u] != fa[k][v])
{
u = fa[k][u];
v = fa[k][v];
}
}
return fa[][u];
}
int KTH(int u, int v, int lca, int k)//从u->v路径上的第k个数
{
if(k == ) return u;
int l1 = dep[u] - dep[lca] + ;//左半枝
int l2 = dep[v] - dep[lca];
if(k <= l1)//在左半枝(lca定义成左半枝)
{
k -= ;
for(int t = ; t >= ; t--)
{
if(k >> t & )
u = fa[t][u];
}
return u;
}
else//在右半枝
{
k -= l1;
k = l2 - k;
for(int t = ; t >= ; t--)
{
if(k >> t & )
v = fa[t][v];
}
return v;
}
}
int main ()
{
scanf("%d", &T);
while(T--)
{
init();
int u, v, ds, k;
char s[];
scanf("%d", &N);
for(int i = ; i < N; i++)
{
scanf("%d%d%d", &u, &v, &ds);
add(u, v, ds);
add(v, u, ds);
}
INIT();
while(scanf("%s", s))
{
if(!strcmp(s, "DONE"))
break;
else if(!strcmp(s, "DIST"))
{
scanf("%d%d", &u, &v);
printf("%d\n", dis[u] + dis[v] - * dis[LCA(u, v)]);
}
else
{
scanf("%d%d%d", &u, &v, &k);
int lca = LCA(u, v);
printf("%d\n", KTH(u, v, lca, k)); }
}
}
return ;
}
SPOJ375 Query on a tree 【倍增,在线】的更多相关文章
- SPOJ375 Query on a tree
Description You are given a tree (an acyclic undirected connected graph) with N nodes, and edges num ...
- SPOJ375 Query on a tree(树链剖分)
传送门 题意 给出一棵树,每条边都有权值,有两种操作: 把第p条边的权值改为x 询问x,y路径上的权值最大的边 code #include<cstdio> #include<algo ...
- SPOJ375 Query on a tree(LCT边权)
之前做了两道点权的LCT,这次做一下边权的LCT.上网找了一下资料,发现对于边权的LCT有这么两种处理方法,一种是每条边建一个点,于是边权就转成点权了.另外一种则是每个边权对应到点权上,也就是每个点对 ...
- spoj 913 Query on a tree II (倍增lca)
Query on a tree II You are given a tree (an undirected acyclic connected graph) with N nodes, and ed ...
- Query on a tree——树链剖分整理
树链剖分整理 树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护. 通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中s ...
- SPOJ 375. Query on a tree (树链剖分)
Query on a tree Time Limit: 5000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Ori ...
- QTREE3 spoj 2798. Query on a tree again! 树链剖分+线段树
Query on a tree again! 给出一棵树,树节点的颜色初始时为白色,有两种操作: 0.把节点x的颜色置反(黑变白,白变黑). 1.询问节点1到节点x的路径上第一个黑色节点的编号. 分析 ...
- spoj 375 Query on a tree(树链剖分,线段树)
Query on a tree Time Limit: 851MS Memory Limit: 1572864KB 64bit IO Format: %lld & %llu Sub ...
- bzoj 3637: Query on a tree VI 树链剖分 && AC600
3637: Query on a tree VI Time Limit: 8 Sec Memory Limit: 1024 MBSubmit: 206 Solved: 38[Submit][Sta ...
随机推荐
- 【CodeForces】576 C. Points on Plane
[题目]C. Points on Plane [题意]给定坐标系中n个点的坐标(范围[0,10^6]),求一种 [ 连边形成链后总长度<=2.5*10^9 ] 的方案.n<=10^6. [ ...
- c++树,知道前序和中序求后序遍历
经常有面试题就是知道一棵树的前序遍历和中序遍历让你写出后序遍历,这个慢慢画是能画出来的,但是要很快的弄出来还是要懂原理. 首先说一下三种遍历:所谓的前序后序和中序都是遍历时遍历根节点的顺序.子树的话依 ...
- 多进程Process
多进程旧式写法 from multiprocessing import Pool def f(x): return x*x if __name__ == '__main__': p = Pool(5) ...
- jquery.cookie.js——jquery的cookie插件
一.JS文件 /*! * jQuery Cookie Plugin v1.4.1 * https://github.com/carhartl/jquery-cookie * * Copyright 2 ...
- cookie、localstroage与sessionstroage的一些优缺点
1. Cookie 在前端开发中,尽量少用cooie,原因: (1) cookie限制大小,约4k左右,不适合存储业务数据,尤其是数据量较大的值: (2) cookie会每次随http请 ...
- 全文搜索引擎 Elasticsearch 介绍
全文搜索属于最常见的需求,开源的 Elasticsearch (以下简称 Elastic)是目前全文搜索引擎的首选. 它可以快速地储存.搜索和分析海量数据.维基百科.Stack Overflow.Gi ...
- php文件上传——php经典实例
php文件上传——php经典实例 表单页 <html> <head> <title>文件上传</title> <meta charset='ut ...
- Spring Boot企业级博客系统实战视频教程
欢迎关注我的微信公众号:"Java面试通关手册" 回复关键字" springboot "免费领取(一个有温度的微信公众号,期待与你共同进步~~~坚持原创,分享美 ...
- makefile里PHONY的相关介绍
Phony Targets PHONY 目标并非实际的文件名:只是在显式请求时执行命令的名字.有两种理由需要使用PHONY 目标:避免和同名文件冲突,改善性能. 如果编写一个规则,并不产生目标文件 ...
- Linux 删除文件后空间不释放【原创】
删除MySQL备份文件后,查找文件所在目录发现文件已经备删除了,但是空间没有释放,还是83% 解决方法: lsof|grep -i delete 发现进程还在,杀掉进程 kill -9 5377 再次 ...