题意:给出树上任意两点,求路径上的值的和与最大值,带单点修改操作

树链剖分思路:

1、对树进行dfs求出点的深度和父亲节点,然后求出轻重儿子(重儿子就是点最多的那个子树,其余都是轻儿子),用一个son数组指向每个节点的重儿子

2、对树进行第二次dfs,对于所有的重儿子,求出他的top节点也就是每个重儿子沿着重链可以到达的最远的那个祖先,然后维护dfs序,记录每个节点的访问次序以及第几次访问的是哪个节点,轻儿子的top节点就是本身

然后我们得到

dfs序:       1 4 9 13 14 8 10 3 7 2 6 11 12 5

top数组: 1 1 1 1 1  8 10 3 3 2 2 2 12 5(对应dfs序)

这样我们就把这棵树拆成了一条条的链(top值相同则为一条链上的点),用线段树维护这个dfs序,就可以快速求出链上最大值和值的和了,

对于任意两点,我们只需依次求出路径上的所有链的答案然后合并即可,可以证明路径上轻重链的条数是不超过logn的,这样单次查询的复杂度为O((logn)^2)

总时间复杂度O(q(logn)^2)

在计算两点答案的时候,采取一个巧妙的方法。首先若两个点不在同一条链上,我们总是让深度更大的那个点x往上跳到top[x],并统计这条链的答案,直到两个点到同一条链上,最后计算在一条链上时的答案即可

AC代码(模板)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+;
struct Edge
{
int v,next;
}edge[N<<];
int sum[N<<],mx[N<<],n;
int head[N],tot,dep[N],fa[N],sz[N],son[N],top[N],id[N],rk[N],cnt,val[N];
void init()
{
memset(head,-, sizeof(head));
tot=;
}
void add(int u,int v)
{
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs1(int u,int f)
{
dep[u]=dep[f]+;
fa[u]=f;
sz[u]=;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].v;
if(v==f)continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
id[u]=++cnt;
rk[cnt]=u;
if(!son[u])return;
dfs2(son[u],t);
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].v;
if(v!=son[u]&&v!=fa[u])dfs2(v,v);
}
}
void pushup(int rt)
{
sum[rt]=sum[rt<<]+sum[rt<<|];
mx[rt]=max(mx[rt<<],mx[rt<<|]);
}
void build(int l,int r,int rt)
{
if(l==r)
{
mx[rt]=sum[rt]=val[rk[l]];
return;
}
int m=(l+r)>>;
build(l,m,rt<<);
build(m+,r,rt<<|);
pushup(rt);
}
int querySum(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)return sum[rt];
int m=(l+r)>>;
int res=;
if(L<=m)res+=querySum(L,R,l,m,rt<<);
if(R>m)res+=querySum(L,R,m+,r,rt<<|);
return res;
}
int queryMax(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)return mx[rt];
int m=(l+r)>>;
int res=-1e9;
if(L<=m)res=max(res,queryMax(L,R,l,m,rt<<));
if(R>m)res=max(res,queryMax(L,R,m+,r,rt<<|));
return res;
}
void update(int pos,int val,int l,int r,int rt)
{
if(l==r){
sum[rt]=mx[rt]=val;
return;
}
int m=(l+r)>>;
if(pos<=m)update(pos,val,l,m,rt<<);
else update(pos,val,m+,r,rt<<|);
pushup(rt);
}
int getSum(int x,int y)
{
int ans=;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=querySum(id[top[x]],id[x],,n,);
x=fa[top[x]];
}
if(id[x]>id[y])swap(x,y);
ans+=querySum(id[x],id[y],,n,);
return ans;
}
int getMax(int x,int y)
{
int ans=-1e9;
while (top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=max(ans,queryMax(id[top[x]],id[x],,n,));
x=fa[top[x]];
}
if(id[x]>id[y])swap(x,y);
ans=max(ans,queryMax(id[x],id[y],,n,));
return ans;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie();
cout.tie();
init();
int u,v;
cin>>n;
for(int i=;i<=n-;i++)
{
cin>>u>>v;
add(u,v);
add(v,u);
}
for(int i=;i<=n;i++)cin>>val[i];
dfs1(,);
dfs2(,);
build(,n,);
int q,x,y;
string op;
cin>>q;
while(q--)
{
cin>>op>>x>>y;
if(op=="QMAX")cout<<getMax(x,y)<<'\n';
else if(op=="QSUM")cout<<getSum(x,y)<<'\n';
else update(id[x],y,,n,);
}
return ;
}

bzoj1036 树的统计 树链剖分模板的更多相关文章

  1. 树的统计Count---树链剖分

    NEFU专项训练十和十一——树链剖分 Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t ...

  2. BZOJ 1036: [ZJOI2008]树的统计Count-树链剖分(点权)(单点更新、路径节点最值、路径求和)模板,超级认真写了注释啊啊啊

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

  3. 算法复习——树链剖分模板(bzoj1036)

    题目: 题目背景 ZJOI2008 DAY1 T4 题目描述 一棵树上有 n 个节点,编号分别为 1 到 n ,每个节点都有一个权值 w .我们将以下面的形式来要求你对这棵树完成一些操作:I.CHAN ...

  4. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

  5. Hdu 5274 Dylans loves tree (树链剖分模板)

    Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...

  6. [luogu P2590 ZJOI2008] 树的统计 (树链剖分)

    题目描述 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w. 我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u ...

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

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

  8. BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)

    潇爷昨天刚刚讲完...感觉得还可以...对着模板打了个模板...还是不喜欢用指针.... 1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Lim ...

  9. BZOJ 1036: [ZJOI2008]树的统计Count (树链剖分模板题)

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

随机推荐

  1. Rust <10>:宏导出、导入

    源 crate 中使用 #[macro_export] 属性标记的宏,调用者可在导入此 crate 时添加 #[macro_use] 属性使用. 没有 #[macro_export] 的宏,外部不可见 ...

  2. layui点击图片放大-多图显示

    layui点击图片放大-多图显示 标签(空格分隔): js HTML // div <div id="photo-list"> <img class=" ...

  3. Java继承方法隐藏(覆盖)

    方法隐藏 一个类从其超类继承所有非私有静态方法.在子类中重新定义继承的静态方法称为方法隐藏.子类中的重定义静态方法隐藏其超类的静态方法.在类中重定义非静态方法称为方法覆盖.关于方法隐藏的重定义方法(名 ...

  4. Python测试代理ip是否有效

    方式一: 通过icanhazip.com返回的ip地址进行检测 import requests '''代理IP地址(高匿)''' proxy = { 'http': 'http://117.85.10 ...

  5. Django中的缓存机制

    概述       对于中等流量网站来说,尽可能的减少开销是必要的.缓存数据就是为了保存那些需要很多计算资源大的结果,这样的的话就不必在下次重复消耗计算资源.     Django自带了一个健壮的缓存系 ...

  6. 15-python基础-元组

    1.元组的定义 Tuple(元组)与列表类似,不同之处在于元组不能修改. 元组表示多个元素组成的序列. 元组在python开发中,有特定的应用场景. 用于存储一串信息,数据之间使用,分割 元组用()定 ...

  7. css雪碧图(精灵图)与字体图标的介绍以及对比

    css雪碧图(精灵图)与字体图标的介绍以及对比 设想一个实际场景:在一个页面为了展示,我们放置了很多独立的小图片,浏览器在显示页面的时候,就需要向服务器就会发送很多请求,来获取并加载这些小图片,但是这 ...

  8. linux下如何挂载磁盘

    1.显示磁盘使用情况:#df 2.显示磁盘:#fdisk -l 3.格式化分区:#mkfs.ext4 /dev/vdb1           //注:将/dev/vdb1格式化为ext4类型(文件类型 ...

  9. termcap - 终端功能数据库

    描述 DESCRIPTION termcap 数据库是一个过时 (obsolete) 工具,用来描述以字符为单位的终端和打印机的功能.它之所以被保留,是为了兼容古老的程序:新程序应当使用 termin ...

  10. Python-UiAutomator2实现Android自动化测试

    本帖转自搜狗测试公众号 [一.前言]        基于Python-UiAutomator2实现Android自动化测试,小编在Android应用的自动化性能测试中进行了实践.本篇将简单介绍pyth ...