树链剖分整理

树链剖分就是把树拆成一系列链,然后用数据结构对链进行维护。

通常的剖分方法是轻重链剖分,所谓轻重链就是对于节点u的所有子结点v,size[v]最大的v与u的边是重边,其它边是轻边,其中size[v]是以v为根的子树的节点个数,全部由重边组成的路径是重路径,根据论文上的证明,任意一点到根的路径上存在不超过logn条轻边和logn条重路径。

这样我们考虑用数据结构来维护重路径上的查询,轻边直接查询。

通常用来维护的数据结构是线段树,splay较少见。

具体步骤

预处理

第一遍dfs

求出树每个结点的深度dep[x],其为根的子树大小siz[x]

,其重儿子,以及祖先的信息fa[x]表示x的直接父亲,

第二遍dfs

根节点为起点,向下拓展构建重链

选择最大的一个子树的根继承当前重链

其余节点,都以该节点为起点向下重新拉一条重链

搞出top[x],top[x]表示x所在链的端点

给每个结点分配一个位置编号,每条重链就相当于一段区间,用数据结构去维护。

搞出pos[x],pos[x]表示在线段树中以x为下端点的标号(一般不维护边)

把所有的重链首尾相接,放到同一个数据结构上,然后维护这一个整体即可

修改操作

1、单独修改一个点的权值    //例题中没用

根据其编号直接在数据结构中修改就行了。

2、修改点u和点v的路径上的权值

(1)若u和v在同一条重链上

直接用数据结构修改pos[u]至pos[v]间的值。

(2)若u和v不在同一条重链上

一边进行修改,一边将u和v往同一条重链上靠,然后就变成了情况(1)。

查询操作

查询操作的分析过程同修改操作

题目不同,选用不同的数据结构来维护值,通常有线段树和splay

  

例题、SPOJ 305:Query on a tree
题意:10000个点的树,有边权(<=1000000),支持两个操作:
1、CHANGE i ti 把第i条变的权改为ti
2、QUERY a b 查询a,b两点间路径上的最大边
20组数据

#include<cstdio>
#include<cstring>
#include<iostream>
#define lc k<<1
#define rc k<<1|1
#define IN inline
#define R register
using namespace std;
const int N=1e4+;
IN int read(){
R int x=;R bool f=;
R char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+ch-'';ch=getchar();}
return f?x:-x;
}
struct node{
int u,v,w,next;
}e[N<<];
int n,T,tot,num,head[N],fa[N],top[N],pos[N],dep[N],siz[N],son[N];
int a[N<<];
void add(int x,int y,int z){
e[++tot].u=x;
e[tot].v=y;
e[tot].w=z;
e[tot].next=head[x];
head[x]=tot;
}
void dfs(int u,int f,int de){
fa[u]=f;dep[u]=de;siz[u]=;
for(int i=head[u],v;i;i=e[i].next){
v=e[i].v;
if(v!=f){
dfs(v,u,de+);
siz[u]+=siz[v];
if(!son[u]||siz[son[u]]<siz[v]){
son[u]=v;
}
}
}
}
void getpos(int u,int tp){
top[u]=tp;
pos[u]=++num;
if(!son[u]) return ;
getpos(son[u],tp);
for(int i=head[u],v;i;i=e[i].next){
v=e[i].v;
if(v!=son[u]&&v!=fa[u]){
getpos(v,v);
}
}
}
void change(int k,int l,int r,int pos,int val){
if(l==r){
a[k]=val;
return;
}
int mid=l+r>>;
if(pos<=mid) change(lc,l,mid,pos,val);
else change(rc,mid+,r,pos,val);
a[k]=max(a[lc],a[rc]);
}
int query(int k,int l,int r,int x,int y){
if(l==x&&y==r) return a[k];
int mid=l+r>>;
if(y<=mid) return query(lc,l,mid,x,y);
else if(x>mid) return query(rc,mid+,r,x,y);
else return max(query(lc,l,mid,x,mid),query(rc,mid+,r,mid+,y));
}
int find(int u,int v){
int tp1=top[u],tp2=top[v],ans=;
while(tp1!=tp2){
if(dep[tp1]<dep[tp2]){
swap(tp1,tp2);
swap(u,v);
}
ans=max(ans,query(,,num,pos[tp1],pos[u]));
u=fa[tp1];tp1=top[u];
}
if(u==v) return ans;
if(dep[u]>dep[v]) swap(u,v);
return max(ans,query(,,num,pos[u]+,pos[v]));
}
void Cl(){
tot=;num=;
memset(a,,sizeof a);
memset(fa,,sizeof fa);
memset(head,,sizeof head);
memset(pos,,sizeof pos);
memset(top,,sizeof top);
memset(son,,sizeof son);
memset(dep,,sizeof dep);
}
int main(){
for(T=read();T--;){
Cl();
n=read();
for(int i=,x,y,z;i<n;i++){
x=read();y=read();z=read();
add(x,y,z);add(y,x,z);
}
dfs(,,);
getpos(,);
for(int i=,t=(n-)*;i<t;i+=){
if(dep[e[i].v]<dep[e[i].u]) swap(e[i].u,e[i].v);
change(,,num,pos[e[i].v],e[i].w);
}
char ch[];
for(int x,y;;){
scanf("%s",ch);
if(ch[]=='D') break;
if(ch[]=='C'){
x=read();y=read();
change(,,num,pos[e[x*-].v],y);
}
else{
x=read();y=read();
printf("%d\n",find(x,y));
}
}
}
return ;
}

 

Query on a tree——树链剖分整理的更多相关文章

  1. SPOJ Query on a tree 树链剖分 水题

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

  2. spoj QTREE - Query on a tree(树链剖分+线段树单点更新,区间查询)

    传送门:Problem QTREE https://www.cnblogs.com/violet-acmer/p/9711441.html 题解: 树链剖分的模板题,看代码比看文字解析理解来的快~~~ ...

  3. SPOJ QTREE Query on a tree 树链剖分+线段树

    题目链接:http://www.spoj.com/problems/QTREE/en/ QTREE - Query on a tree #tree You are given a tree (an a ...

  4. spoj 375 Query on a tree (树链剖分)

    Query on a tree You are given a tree (an acyclic undirected connected graph) with N nodes, and edges ...

  5. spoj 375 QTREE - Query on a tree 树链剖分

    题目链接 给一棵树, 每条边有权值, 两种操作, 一种是将一条边的权值改变, 一种是询问u到v路径上最大的边的权值. 树链剖分模板. #include <iostream> #includ ...

  6. SPOJ QTREE Query on a tree ——树链剖分 线段树

    [题目分析] 垃圾vjudge又挂了. 树链剖分裸题. 垃圾spoj,交了好几次,基本没改动却过了. [代码](自带常数,是别人的2倍左右) #include <cstdio> #incl ...

  7. SPOJ 375 Query on a tree 树链剖分模板

    第一次写树剖~ #include<iostream> #include<cstring> #include<cstdio> #define L(u) u<&l ...

  8. SPOJ QTREE Query on a tree --树链剖分

    题意:给一棵树,每次更新某条边或者查询u->v路径上的边权最大值. 解法:做过上一题,这题就没太大问题了,以终点的标号作为边的标号,因为dfs只能给点分配位置,而一棵树每条树边的终点只有一个. ...

  9. Query on a tree 树链剖分 [模板]

    You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...

随机推荐

  1. 高仿精仿手机版QQ空间应用源码

    说明:本次QQ空间更新了以前非常基础的代码 更新内容一 更新了登陆界面二  增加了输入时密码时和登陆成功后播放音频的效果三 增加了导航条渐隐的效果(和真实QQ空间的导航条一样,首先透明,当tablev ...

  2. Bootstrap分页插件--Bootstrap Paginator

    开源中国有一篇介绍的很详细,链接:https://my.oschina.net/shunshun/blog/204587 使用这个插件和使用其他Bootstrap内置的插件一样,需要引入如下文件: & ...

  3. Spring MVC 原理小结

    主要由DispatcherServlet.处理器映射.处理器.视图解析器.视图组成   1.DispatcherServlet接收到一个HTTP请求,根据对应配置文件中的处理机映射,找到处理器(Han ...

  4. nodejs get/request

    灌水评论示例: var http = require('http'); var querystring = require('querystring'); var postData = queryst ...

  5. js 事件处理程序 事件对象

    事件:用户或浏览器自身执行的动作: 事件处理程序:响应某个事件的函数: 事件流:从页面中接收事件的顺序. 1.DOM事件流 "DOM2级事件"规定的事件流包括三个阶段:事件捕获阶段 ...

  6. 面试题整理:SQL(一)

    1.横纵表转换 A表 Name Course Grade Alex English 80 Alex Chinese 70 Alex Japanese 85 Bob English 75 Bob Chi ...

  7. 详解javascript,ES5标准中新增的几种高效Object操作方法

    1.Object 对象 (JavaScript) 提供对所有 JavaScript 对象通用的功能.参考网站:https://msdn.microsoft.com/zh-cn/library/kb6t ...

  8. react学习笔记1

    # 1.hello world 学习一个语言,最好的方式,我们需要去官网去查看文档(https://facebook.github.io/react),通过JSFiddle,便可以看到最简单的demo ...

  9. SQL Server(九)——事务

    事务: 保障流程的完整执行,就像银行取钱,先在你账上扣钱,然后存入别人的账上:但是从你账上扣完钱了,突然网断了,对方没有收到钱,那么此时你的钱也没了,别人的钱也没加上,事务为了防止此类情况的出现. 事 ...

  10. SQL Server 2012实施与管理实战指南(笔记)——Ch3Alwayson可用组

    3.AlwaysOn可用组 Alwayson支持的,是一个可用性组,每个可用性组是包含了多个用户数据库的容器,可用性组内的数据库可以作为一个整体进行故障转移. AlwaysOn关键特性: 一.类似集群 ...