【loj#139】树链剖分
#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】树链剖分的更多相关文章
- LOJ#139. 树链剖分
LOJ#139. 树链剖分 题目描述 这是一道模板题. 给定一棵$n$个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值.下面依次进行 m 个操作,操作分为如下五种类型: 换根:将一个 ...
- LibreOJ #139 树链剖分 [树链剖分,线段树]
题目传送门 树链剖分 题目描述 这是一道模板题. 给定一棵 n 个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值.下面依次进行 m 个操作,操作分为如下五种类型: 换根:将一个指定的 ...
- BZOJ 2157: 旅游( 树链剖分 )
树链剖分.. 样例太大了根本没法调...顺便把数据生成器放上来 -------------------------------------------------------------------- ...
- LOJ2269 [SDOI2017] 切树游戏 【FWT】【动态DP】【树链剖分】【线段树】
题目分析: 好题.本来是一道好的非套路题,但是不凑巧的是当年有一位国家集训队员正好介绍了这个算法. 首先考虑静态的情况.这个的DP方程非常容易写出来. 接着可以注意到对于异或结果的计数可以看成一个FW ...
- NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分
原文链接https://www.cnblogs.com/zhouzhendong/p/9275606.html 题目传送门 - 洛谷P1600 题目传送门 - LOJ#2359 题目传送门 - Vij ...
- 树链剖分(附带LCA和换根)——基于dfs序的树上优化
.... 有点懒: 需要先理解几个概念: 1. LCA 2. 线段树(熟练,要不代码能调一天) 3. 图论的基本知识(dfs序的性质) 这大概就好了: 定义: 1.重儿子:一个点所连点树size最大的 ...
- BZOJ_2243 [SDOI2011]染色 【树链剖分+线段树】
一 题目 [SDOI2011]染色 二 分析 感觉树链剖分的这些题真的蛮考验码力的,自己的码力还是不够啊!o(╯□╰)o 还是比较常规的树链剖分,但是一定记得这里的线段树在查询的时候一定要考虑链于链相 ...
- BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】
一 题目 [HAOI2015]树上操作 二 分析 树链剖分的题,这里主要用到了$dfs$序,这题比较简单的就是不用求$lca$. 1.和树链剖分一样,先用邻接链表建双向图. 2.跑两遍$dfs$,其实 ...
- SPOJ QTree【树链剖分】
一 题目 QTREE 二 分析 第一道树链剖分的题,写的好艰难啊. 题意还是比较好理解的,就是在树上操作. 对于修改,题中要求的是单点修改,就算是直接树上操作也是非常简单的. 对于查询,查询的时候,是 ...
随机推荐
- jmeter逻辑控制器
刚开始学习,只写几种了解的逻辑控制器 1.简单控制器 只用来组合采样器和其他逻辑控制器,不影响jmeter的运行 2.循环控制器 用来循环执行采样器和其他逻辑控制器,例如一个用户发送特定请求多次,即可 ...
- Spring Cloud(一):服务治理技术概览【Finchley 版】
Spring Cloud(一):服务治理技术概览[Finchley 版] 发表于 2018-04-14 | 更新于 2018-05-07 | Spring Cloud Netflix 是 Spr ...
- 433. Number of Islands【LintCode java】
Description Given a boolean 2D matrix, 0 is represented as the sea, 1 is represented as the island. ...
- 3星|李开复《AI·未来》:中国创业公司有独特优势,人工智能可能会加剧社会的不平等与不稳定
主要内容:作者对自己一些经历的回顾,对中美两国人工智能行业的回顾与展望. 作者认为中国的创业公司比美国节奏更快工作更拼命,深圳在硬件创新上远远领先于美国,中国创业公司们走出了一条跟美国不同的路. 作者 ...
- 使用Firebug或chrome-devToolBar深入学习javascript语言核心
使用Firebug和chrome-devToolBar调试页面样式或脚本是前端开发每天必做之事.这个开发神器到底能给我们带来哪些更神奇的帮助呢?这几天看的一些资料中给了我启发,能不通过Firebug和 ...
- Teaching Machines to Understand Us 让机器理解我们 之一 引言
Teaching Machines to Understand Us By Tom Simonite MIT Technology Review Vol.118 No.5 2015 让机器理解我 ...
- 解决xampp启动mysql失败
进入到注册表内 命令:regedit 进入到路径:计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\MySQL 修改路径为:" ...
- Python数据挖掘——数据预处理
Python数据挖掘——数据预处理 数据预处理 数据质量 准确性.完整性.一致性.时效性.可信性.可解释性 数据预处理的主要任务 数据清理 数据集成 数据归约 维归约 数值归约 数据变换 规范化 数据 ...
- JVM监控及堆栈内存
jconsole 堆内存:存放new出来的对象 栈内存:存放基本数据结构和对象的引用,但对象本身放在堆中
- 从无到有之webpack+vuerouter的简单例子以及各个属性解释
之前一直没玩过webpack和vue,近两周才看这玩意,本文纯属自己的实验+之前angular作战经验的理解一些入门文章 首先webpack关于vue以及各个包 module.exports = { ...