#139. 树链剖分

题目描述

这是一道模板题。

给定一棵 $n$个节点的树,初始时该树的根为 111 号节点,每个节点有一个给定的权值。下面依次进行 $m$ 个操作,操作分为如下五种类型:

  • 换根:将一个指定的节点设置为树的新根。

  • 修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值。

  • 修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值。

  • 询问路径:询问某条路径上节点的权值和。

  • 询问子树:询问某个子树内节点的权值和

输入格式

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

第二行 n 个整数表示第 iii 个节点的初始权值 $a_i$​。

第三行 n−1 个整数,表示 i+1i+1i+1 号节点的父节点编号$ fi+1 (1⩽fi+1⩽n)f_{i+1}\ (1 \leqslant f_{i+1} \leqslant n)fi+1​ (1⩽fi+1​⩽n)。$

第四行一个整数 m,表示操作个数。

接下来 m 行,每行第一个整数表示操作类型编号:$(1⩽u,v⩽n)(1 \leqslant u, v \leqslant n)(1⩽u,v⩽n)$

  • 若类型为 111,则接下来一个整数 u,表示新根的编号。

  • 若类型为 222,则接下来三个整数 u,v,ku,v,ku,v,k,分别表示路径两端的节点编号以及增加的权值。

  • 若类型为 333,则接下来两个整数 u,ku,ku,k,分别表示子树根节点编号以及增加的权值。

  • 若类型为 444,则接下来两个整数 u,vu,vu,v,表示路径两端的节点编号。

  • 若类型为 555,则接下来一个整数 u,表示子树根节点编号。

输出格式

对于每一个类型为 444 或 555 的操作,输出一行一个整数表示答案。

样例
样例输入
6
1 2 3 4 5 6
1 2 1 4 4
6
4 5 6
2 2 4 1
5 1
1 4
3 1 2
4 2 5
样例输出
15
24
19
数据范围与提示

对于 $100%100\%100%$ 的数据,$1⩽n,m,k,ai⩽1051\leqslant n,m,k,a_i\leqslant 10^51⩽n,m,k,ai​⩽105$。数据有一定梯度。

题意:树链加,子树加,需要支持换根,查询树链和,子树和

题解:

树链剖分模板,树链加和查询直接树链剖分即可,

注意到树链剖分有个很方便的性质就是链剖的序列其实也是dfs序,记录一个点的序列上起点和终点就可以顺便维护子树,

换根的话分类讨论一下,一直以1号点为根,对树链的修查无影响,考虑子树:

假设访问u号点,在以1号点为根的形态下:

当前根rt,如果u==rt则u的子树为整个以1为根的树,

如果rt是u的子树里的节点,那么u所代表的的子树就是整个子树 - rt的祖先里u的儿子的  子树 ,

如果rt不是u的子树里的节点,那么u的子树就是以1为根时u的子树;

这样操作后也是区间,可以和前两个一起维护;

 #include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#include<vector>
#include<stack>
#include<map>
#define ls (k<<1)
#define rs (k<<1|1)
#define Run(i,l,r) for(int i=l;i<=r;i++)
#define Don(i,l,r) for(int i=l;i>=r;i--)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int N=;
int n,m,o,hd[N],tp[N],st[N],ed[N],idx,son[N],fa[N],w[N],sz[N],dep[N],root;//
ll val[N],sum[N<<],ly[N<<];//
struct Edge{int v,nt;}E[N<<]; //
char gc(){
static char*p1,*p2,s[];
if(p1==p2)p2=(p1=s)+fread(s,,,stdin);
return(p1==p2)?EOF:*p1++;
}//
int rd(){
int x=,f=; char c=gc();
while(c<''||c>''){if(c=='-')f=-;c=gc();}
while(c>=''&&c<=''){x=(x<<)+(x<<)+c-'',c=gc();}
return x*f;
}//
void adde(int u,int v){
E[o]=(Edge){v,hd[u]};hd[u]=o++;
E[o]=(Edge){u,hd[v]};hd[v]=o++;
}//
void dfsA(int u,int F){
dep[u]=dep[F]+;
son[u]=; sz[u]=;
for(int i=hd[u];~i;i=E[i].nt){
int v=E[i].v;
if(v==F)continue;
dfsA(v,u);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])son[u]=v;
}
}//
void dfsB(int u,int T){
tp[u]=T; val[st[u]=++idx]=w[u];
if(son[u])dfsB(son[u],T);
for(int i=hd[u];~i;i=E[i].nt){
int v=E[i].v;
if(v==son[u]||v==fa[u])continue;
dfsB(v,v);
}
ed[u]=idx;
}//
void pushup(int k){sum[k]=sum[ls]+sum[rs];}//
void mfy(int k,int l,int r,ll v){sum[k]+=v*(r-l+);ly[k]+=v;}//
void pushdown(int k,int l,int r){
if(ly[k]){
int mid=(l+r)>>;
mfy(ls,l,mid,ly[k]);
mfy(rs,mid+,r,ly[k]);
ly[k]=;
}
}//
void build(int k,int l,int r){
if(l==r){sum[k]=val[l];ly[k]=;return;}
int mid=(l+r)>>;
build(ls,l,mid);
build(rs,mid+,r);
pushup(k);
}//
void update(int k,int l,int r,int x,int y,ll v){
if(l==x&&r==y)mfy(k,l,r,v);
else {
pushdown(k,l,r);
int mid=(l+r)>>;
if(y<=mid)update(ls,l,mid,x,y,v);
else if(x>mid)update(rs,mid+,r,x,y,v);
else update(ls,l,mid,x,mid,v) , update(rs,mid+,r,mid+,y,v);
pushup(k);
}
}//
ll query(int k,int l,int r,int x,int y){
if(l==x&&r==y)return sum[k];
else {
pushdown(k,l,r);
int mid=(l+r)>>;
if(y<=mid)return query(ls,l,mid,x,y);
else if(x>mid)return query(rs,mid+,r,x,y);
else return query(ls,l,mid,x,mid) + query(rs,mid+,r,mid+,y);
}
}//
int child(int u,int v){
while(tp[u]!=tp[v]){
u=tp[u];
if(fa[u]==v)return u;
u=fa[u];
}
return son[v];
}//
void update1(int u,int v,int x){
while(tp[u]!=tp[v]){
if(dep[tp[u]]<dep[tp[v]])swap(u,v);
update(,,n,st[tp[u]],st[u],x);
u=fa[tp[u]];
}
if(dep[u]<dep[v])swap(u,v);
update(,,n,st[v],st[u],x);
}//
void update2(int u,int x){
if(u==root){update(,,n,,n,x);}
else if(st[u]<=st[root]&&ed[root]<=ed[u]){
int t = child(root,u);
update(,,n,,n,x);
update(,,n,st[t],ed[t],-x);
}
else{update(,,n,st[u],ed[u],x);}
}//
void query1(int u,int v){
ll ret=;
while(tp[u]!=tp[v]){
if(dep[tp[u]]<dep[tp[v]])swap(u,v);
ret += query(,,n,st[tp[u]],st[u]);
u=fa[tp[u]];
}
if(dep[u]<dep[v])swap(u,v);
ret += query(,,n,st[v],st[u]);
printf("%lld\n",ret);
}//
void query2(int u){
ll ret=;
if(u==root)ret=query(,,n,,n);
else if(st[u]<=st[root]&&ed[root]<=ed[u]){
int t = child(root,u);
ret += query(,,n,,n);
ret -= query(,,n,st[t],ed[t]);
}
else{ret = query(,,n,st[u],ed[u]);}
printf("%lld\n",ret);
}//
int main(){
//freopen("loj139.in","r",stdin);
//freopen("loj139.out","w",stdout);
n=rd();
for(int i=;i<=n;i++)w[i]=rd(),hd[i]=-;
for(int i=;i<=n;i++)adde(fa[i]=rd(),i);
dfsA(root=,);dfsB(,);
build(,,n);
m=rd();
for(int i=,u,v,x;i<=m;i++){
int op=rd();
if(op==)root=rd();
else if(op==){u=rd();v=rd();x=rd();update1(u,v,x);}
else if(op==){u=rd();x=rd();update2(u,x);}
else if(op==){u=rd();v=rd();query1(u,v);}
else {u=rd();query2(u);}
}
return ;
}//by tkys_Austin;

【loj#139】树链剖分的更多相关文章

  1. LOJ#139. 树链剖分

    LOJ#139. 树链剖分 题目描述 这是一道模板题. 给定一棵$n$个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值.下面依次进行 m 个操作,操作分为如下五种类型: 换根:将一个 ...

  2. LibreOJ #139 树链剖分 [树链剖分,线段树]

    题目传送门 树链剖分 题目描述 这是一道模板题. 给定一棵 n 个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值.下面依次进行 m 个操作,操作分为如下五种类型: 换根:将一个指定的 ...

  3. BZOJ 2157: 旅游( 树链剖分 )

    树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...

  4. LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】

    题目分析: 好题.本来是一道好的非套路题,但是不凑巧的是当年有一位国家集训队员正好介绍了这个算法. 首先考虑静态的情况.这个的DP方程非常容易写出来. 接着可以注意到对于异或结果的计数可以看成一个FW ...

  5. NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分

    原文链接https://www.cnblogs.com/zhouzhendong/p/9275606.html 题目传送门 - 洛谷P1600 题目传送门 - LOJ#2359 题目传送门 - Vij ...

  6. 树链剖分(附带LCA和换根)——基于dfs序的树上优化

    .... 有点懒: 需要先理解几个概念: 1. LCA 2. 线段树(熟练,要不代码能调一天) 3. 图论的基本知识(dfs序的性质) 这大概就好了: 定义: 1.重儿子:一个点所连点树size最大的 ...

  7. BZOJ_2243 [SDOI2011]染色 【树链剖分+线段树】

    一 题目 [SDOI2011]染色 二 分析 感觉树链剖分的这些题真的蛮考验码力的,自己的码力还是不够啊!o(╯□╰)o 还是比较常规的树链剖分,但是一定记得这里的线段树在查询的时候一定要考虑链于链相 ...

  8. BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】

    一 题目 [HAOI2015]树上操作 二 分析 树链剖分的题,这里主要用到了$dfs$序,这题比较简单的就是不用求$lca$. 1.和树链剖分一样,先用邻接链表建双向图. 2.跑两遍$dfs$,其实 ...

  9. SPOJ QTree【树链剖分】

    一 题目 QTREE 二 分析 第一道树链剖分的题,写的好艰难啊. 题意还是比较好理解的,就是在树上操作. 对于修改,题中要求的是单点修改,就算是直接树上操作也是非常简单的. 对于查询,查询的时候,是 ...

随机推荐

  1. jmeter逻辑控制器

    刚开始学习,只写几种了解的逻辑控制器 1.简单控制器 只用来组合采样器和其他逻辑控制器,不影响jmeter的运行 2.循环控制器 用来循环执行采样器和其他逻辑控制器,例如一个用户发送特定请求多次,即可 ...

  2. Spring Cloud(一):服务治理技术概览【Finchley 版】

    Spring Cloud(一):服务治理技术概览[Finchley 版]  发表于 2018-04-14 |  更新于 2018-05-07 |  Spring Cloud Netflix 是 Spr ...

  3. 433. Number of Islands【LintCode java】

    Description Given a boolean 2D matrix, 0 is represented as the sea, 1 is represented as the island. ...

  4. 3星|李开复《AI·未来》:中国创业公司有独特优势,人工智能可能会加剧社会的不平等与不稳定

    主要内容:作者对自己一些经历的回顾,对中美两国人工智能行业的回顾与展望. 作者认为中国的创业公司比美国节奏更快工作更拼命,深圳在硬件创新上远远领先于美国,中国创业公司们走出了一条跟美国不同的路. 作者 ...

  5. 使用Firebug或chrome-devToolBar深入学习javascript语言核心

    使用Firebug和chrome-devToolBar调试页面样式或脚本是前端开发每天必做之事.这个开发神器到底能给我们带来哪些更神奇的帮助呢?这几天看的一些资料中给了我启发,能不通过Firebug和 ...

  6. Teaching Machines to Understand Us 让机器理解我们 之一 引言

    Teaching Machines to Understand Us   By Tom Simonite  MIT Technology Review Vol.118 No.5 2015 让机器理解我 ...

  7. 解决xampp启动mysql失败

    进入到注册表内 命令:regedit 进入到路径:计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MySQL 修改路径为:" ...

  8. Python数据挖掘——数据预处理

    Python数据挖掘——数据预处理 数据预处理 数据质量 准确性.完整性.一致性.时效性.可信性.可解释性 数据预处理的主要任务 数据清理 数据集成 数据归约 维归约 数值归约 数据变换 规范化 数据 ...

  9. JVM监控及堆栈内存

    jconsole 堆内存:存放new出来的对象 栈内存:存放基本数据结构和对象的引用,但对象本身放在堆中

  10. 从无到有之webpack+vuerouter的简单例子以及各个属性解释

    之前一直没玩过webpack和vue,近两周才看这玩意,本文纯属自己的实验+之前angular作战经验的理解一些入门文章 首先webpack关于vue以及各个包 module.exports = { ...