知识点-树链剖分

  “在一棵树上进行路径的修改、求极值、求和”:乍一看只要线段树就能轻松解决,实际上,仅凭线段树是不能搞定它的。我们需要用到一种貌似高级的复杂算法——树链剖分

     树链,就是树上的路径。剖分,就是把路径分类为重链和轻链。

  记siz[v]表示以v为根的子树的节点数,dep[v]表示v的深度(根深度为1),top[v]表示v所在的链的顶端节点,f[v]表示v的父亲,son[v]表示v的子节点中siz[]最大的节点编号(即重儿子),id[v]表示v的父边在线段树中的位置。只要把这些东西求出来,就能用log(n)的时间完成原问题中的操作。

重儿子:如果siz[u]为v的子节点中siz值最大的,那么u就是v的重儿子。
     轻儿子:v的其它子节点。
     重边:点v与其重儿子的连边。
     轻边:点v与其轻儿子的连边。
     重链:由重边连成的路径。
     轻链:轻边。

算法实现

  首先用一个dfs函数求出siz,dep,f,son的值。

  紧接着用一个build函数建树建链并求出id和top的值。对于节点v,如果有son[v]的存在,显然可得top[son[v]]=top[v]。在线段树中,节点的重边应当在节点的父边之后,所以id[son[v]]=++tot;在对重儿子进行深搜之后,枚举所有轻儿子。对于每个轻儿子u,显然有top[u]=u;同时也要id[top[u]]=++tot;

  当建树建链的步骤完成后,可以根据题意进行相应的操作。

例题

题目描述

一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作:

I. CHANGE u t : 把结点u的权值改为t

II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

注意:从点u到点v的路径上的节点包括u和v本身

输入

输入的第一行为一个整数n,表示节点的个数。

接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。

接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。

接下来1行,为一个整数 q,表示操作的总数。

接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。

输出

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

样例输入

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4

样例输出

4
1
2
2
10
6
5
6
5
16

提示

对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

算法操作

  1.修改操作update:本题只是单点更新,所以只需用普通的线段树修改方法即可。

  2.求极值以及和问题fmax和fsum:属于同一种类型的题目。

  首先记fu=top[u],fv=top[v]。

  若fu!=fv,即它们不处于同一条重链上,则不妨设dep[u]>=dep[v],此时u的深度比v的要大。更新u到fu父边的答案后,使u=f[fu],即将u类似LCA一样向上“跳”。

  若fu=fv,则它们处于同一条重链上。若u!=v,则继续更新答案,否则得到答案。

代码

 #include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define mid ((L+R)>>1)
#define ls (node<<1)
#define rs ls+1
using namespace std;
struct edge{
int to,nxt;
}edge[];
int cnt,n,tot;
int tsum[],tmax[],dep[],id[],head[],f[],son[],siz[],top[];
char ord[];
void add(int u,int v)//链式前向星
{
edge[++cnt].to=v;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
void dfs(int node,int father,int deep)
{
f[node]=father;dep[node]=deep;siz[node]=;
for(int i=head[node];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to==father)continue;
dfs(to,node,deep+);
siz[node]+=siz[to];
if(siz[to]>siz[son[node]])son[node]=to;
}
}
void build(int node,int num)//建树建链
{
id[node]=++tot;
top[node]=num;
if(son[node])build(son[node],num);
for(int i=head[node];i;i=edge[i].nxt)
{
int to=edge[i].to;
if(to!=son[node]&&to!=f[node])build(to,to);
}
}
void update(int node,int L,int R,int u,int w)//更新节点
{
if(u>R||u<L)return;
if(L==R)
{
tsum[node]=tmax[node]=w;
return;
}
update(ls,L,mid,u,w);
update(rs,mid+,R,u,w);
tmax[node]=max(tmax[ls],tmax[rs]);
tsum[node]=tsum[ls]+tsum[rs];
}
int qmax(int node,int L,int R,int l,int r)
{
if(l>R||r<L)return -;
if(l<=L&&R<=r)return tmax[node];
int ans=max(qmax(ls,L,mid,l,r),qmax(rs,mid+,R,l,r));
return ans;
}
int qsum(int node,int L,int R,int l,int r)
{
if(l>R||r<L)return ;
if(l<=L&&R<=r)return tsum[node];
int ans=qsum(ls,L,mid,l,r)+qsum(rs,mid+,R,l,r);
return ans;
}
int fmax(int u,int v)
{
int ans=-;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
ans=max(ans,qmax(,,tot,id[top[u]],id[u]));
u=f[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
ans=max(ans,qmax(,,tot,id[u],id[v]));
return ans;
}
int fsum(int u,int v)
{
int ans=;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])swap(u,v);
ans+=qsum(,,tot,id[top[u]],id[u]);
u=f[top[u]];
}
if(dep[u]>dep[v])swap(u,v);
ans+=qsum(,,tot,id[u],id[v]);
return ans;
}
int main()
{
int a,b,w,u,v,q;
scanf("%d",&n);
for(int i=;i<n;i++)
{
scanf("%d%d",&a,&b);
add(b,a);add(a,b);
}
dfs(,,);
build(,);
for(int i=;i<=n;i++)
{
scanf("%d",&w);
update(,,tot,id[i],w);
}
scanf("%d",&q);
while(q--)
{
scanf("%s%d%d",ord,&u,&v);
if(ord[]=='C')update(,,tot,id[u],v);
else
{
if(ord[]=='M')printf("%d\n",fmax(u,v));
else printf("%d\n",fsum(u,v));
}
}
return ;
}

ZJOI2008树的统计Count的更多相关文章

  1. BZOJ 1036: [ZJOI2008]树的统计Count [树链剖分]【学习笔记】

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 14302  Solved: 5779[Submit ...

  2. bzoj1036 [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 12646  Solved: 5085 [Subm ...

  3. BZOJ 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 14354  Solved: 5802 [Subm ...

  4. 【BZOJ1036】[ZJOI2008]树的统计Count 树链剖分

    [BZOJ1036][ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. ...

  5. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit ...

  6. Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 11102  Solved: 4490[Submit ...

  7. 数据结构(LCT动态树):BZOJ 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 12266  Solved: 4945[Submit ...

  8. BZOJ 1036: [ZJOI2008]树的统计Count( 树链剖分 )

    树链剖分... 不知道为什么跑这么慢 = = 调了一节课啊跪.. ------------------------------------------------------------------- ...

  9. 1036: [ZJOI2008]树的统计Count

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 7496  Solved: 3078[Submit] ...

  10. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

    [ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...

随机推荐

  1. v3学院带您一起学习FPGA

    本文为原创,转载请注明! 课程名称:双buffer乒乓操作项目概况:使用FPGA内部ram作为缓冲器,实现对外部数据流的缓存:为了提升数据的传输及处理速度,在此节课中将用到两个ram进行乒乓操作.结构 ...

  2. 用stm32f0x建立新的工程重要步骤

    stm32f10x系列新建空的工程主要原理: 1.添加启动文件 不同的芯片类型的启动文件的容量是不同的,选择适合该芯片的容量作为启动文件. 注意:启动文件是汇编语言编写的,所以文件的后缀名为.s 2. ...

  3. 2017-03-10 T-sql 语句 高级查询

    T-SQL语句: 创建数据库: 1,点击新建查询,在弹出的页面上进行代码编写.点击可用数据库,编写前确定当前操作的页面是自己想要进行操作的界面. 2,数据库创建语句 Create datebase   ...

  4. 求助,如何干掉这个不要脸的“流氓”

      问题 chrome 第一次打开时,被一个加"7654 导航"的网站捆绑. 查看设置中启动页中,被设置如下:   解决   域名查看,阿里竟然为这样的网站搞隐私保护   尝试 安 ...

  5. 最大化最小值 Aggressive cows

    Aggressive cows http://poj.org/problem?id=2456 N间小屋,M头牛,使得牛跟牛之间的距离最远,以防止牛打架. 2<=N<=100000 2< ...

  6. linux版powershell安装教程(.net core版)

    powershell 传教士 原创文章 始于2016-12-20,2017-03-15改.文章版本目前博客园为最新版. 允许转载,但必须保留名字和出处,否则追究法律责任 问:powershell二进制 ...

  7. 获取 metadata 的完整例子 - 每天5分钟玩转 OpenStack(166)

    我们将通过实验详细分析 instance 从 nova-api-metadata 获取信息的完整过程. 环境介绍 1. 一个 all-in-one 环境(多节点类似). 2. 已创建 neutron ...

  8. Mac端SVN工具CornerStone详解

    俗话说:"工欲善其事必先利其器": 对于我们程序员来说,不管你是大神,还是小鱼小虾,进入公司之后,都用过源码管理工具,不然你就不是一个合格的程序员,现在各个公司用于源码管理工具通常 ...

  9. 如何用 JavaScript 下载文件

    简介 我们知道,下载文件是一个非常常见的需求,但由于浏览器的安全策略的限制,我们通常只能通过一个额外的页面,访问某个文件的 url 来实现下载功能,但是这种用户体验非常不好. 幸好,HTML 5 里面 ...

  10. 【Java基础 】Java7 NIO Files,Path 操作文件

    从Java1.0到1.3,我们在开发需要I/O支持的应用时,要面临以下问题: 没有数据缓冲区或通道的概念,开发人员要编程处理很多底层细节 I/O操作会被阻塞,扩展能力有限 所支持的字符集编码有限,需要 ...