LibreOJ #139 树链剖分 [树链剖分,线段树]
树链剖分
题目描述
这是一道模板题。
给定一棵 n 个节点的树,初始时该树的根为 1 号节点,每个节点有一个给定的权值。下面依次进行 m 个操作,操作分为如下五种类型:
换根:将一个指定的节点设置为树的新根。
修改路径权值:给定两个节点,将这两个节点间路径上的所有节点权值(含这两个节点)增加一个给定的值。
修改子树权值:给定一个节点,将以该节点为根的子树内的所有节点权值增加一个给定的值。
询问路径:询问某条路径上节点的权值和。
询问子树:询问某个子树内节点的权值和。
输入格式
第一行为一个整数 n,表示节点的个数。
第二行 nn个整数表示第 i 个节点的初始权值 ai。
第三行 n−1 个整数,表示i+1 号节点的父节点编号 $f_{i+1}\ (1 \leqslant f_{i+1} \leqslant n)$。
第四行一个整数 m,表示操作个数。
接下来 m 行,每行第一个整数表示操作类型编号:$(1 \leqslant u, v \leqslant n)$
若类型为 1,则接下来一个整数 u,表示新根的编号。
若类型为 2,则接下来三个整数 u,v,k,分别表示路径两端的节点编号以及增加的权值。
若类型为 3,则接下来两个整数 u,k,分别表示子树根节点编号以及增加的权值。
若类型为 4,则接下来两个整数 u,v,表示路径两端的节点编号。
若类型为 5,则接下来一个整数 u,表示子树根节点编号。
输出格式
对于每一个类型为 4 或 5 的操作,输出一行一个整数表示答案。
样例
样例输入
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% 的数据,$1\leqslant n,m,k,a_i\leqslant 10^5$。数据有一定梯度。
分析:
虽然说是树剖模板,但是这个换根操作确实清奇。。。在集训的时候遇到了这题,当时反正是弃疗了。。。实际上换根操作并没有什么影响,在修改查询的时候判断一下就可以了。
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+;
int n,m,root,a[N],head[N],cnt,fa[N],dep[N];
int top[N],dfn[N],num[N],id,size[N],hson[N];
struct Node{int to,next;}edge[N<<];
struct Seg{
ll seg[N<<],sign[N<<];
void pushup(int rt)
{
seg[rt]=seg[rt<<]+seg[rt<<|];
}
void pushdown(int l,int r,int rt)
{
if(!sign[rt])return;
int mid=(l+r)>>;
seg[rt<<]+=sign[rt]*(mid-l+);
seg[rt<<|]+=sign[rt]*(r-mid);
sign[rt<<]+=sign[rt];
sign[rt<<|]+=sign[rt];
sign[rt]=;
}
void build(int l,int r,int rt)
{
if(l>r)return;
if(l==r){
seg[rt]=a[dfn[l]];return;}
int mid=(l+r)>>;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
pushup(rt);
}
void update(int l,int r,int rt,int L,int R,ll C)
{
if(l>R||r<L)return;
if(L<=l&&r<=R){
seg[rt]+=(r-l+)*C;sign[rt]+=C;return;}
int mid=(l+r)>>;
pushdown(l,r,rt);
if(L<=mid)update(l,mid,rt<<,L,R,C);
if(R>mid)update(mid+,r,rt<<|,L,R,C);
pushup(rt);
}
ll quary(int l,int r,int rt,int L,int R)
{
if(l>R||r<L)return ;
if(L<=l&&r<=R){return seg[rt];}
int mid=(l+r)>>;ll ret=;
pushdown(l,r,rt);
if(L<=mid)ret+=quary(l,mid,rt<<,L,R);
if(R>mid)ret+=quary(mid+,r,rt<<|,L,R);
return ret;
}
}T;
inline int read()
{
char ch=getchar();int num=;bool flag=false;
while(ch<''||ch>''){if(ch=='-')flag=true;ch=getchar();}
while(ch>=''&&ch<=''){num=num*+ch-'';ch=getchar();}
return flag?-num:num;
}
inline void add(int x,int y)
{
edge[++cnt].to=y;
edge[cnt].next=head[x];
head[x]=cnt;
}
inline void dfs1(int u)
{
size[u]=;
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].to;if(v==fa[u])continue;
fa[v]=u;dep[v]=dep[u]+;
dfs1(v);size[u]+=size[v];
if(size[v]>size[hson[u]])hson[u]=v;
}
}
inline void dfs2(int u,int now)
{
top[u]=now;num[u]=++id;dfn[id]=u;
if(!hson[u])return;dfs2(hson[u],now);
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].to;
if(v==fa[u]||v==hson[u])continue;
dfs2(v,v);}
}
inline int check(int x)
{
if(x==root)return -;
if(!(num[x]<num[root]&&num[x]+size[x]->=num[root]))return ;
int now=root;
while(dep[now]>dep[x]){if(fa[top[now]]==x)return top[now];now=fa[top[now]];}
return hson[x];
}
inline void modify_path(int x,int y,ll z)
{
int fax=top[x],fay=top[y];
while(fax!=fay){
if(dep[fax]<dep[fay]){
swap(fax,fay);swap(x,y);}
T.update(,n,,num[fax],num[x],z);
x=fa[fax];fax=top[x];}
if(dep[x]>dep[y])swap(x,y);
T.update(,n,,num[x],num[y],z);
}
inline int modify_tree(int x,ll y)
{
int ka=check(x);
switch (ka){
case -:T.update(,n,,,n,y);break;
case :T.update(,n,,num[x],num[x]+size[x]-,y);break;
default:T.update(,n,,,n,y);T.update(,n,,num[ka],num[ka]+size[ka]-,-y);break;
}
}
inline ll quary_path(int x,int y)
{
int fax=top[x],fay=top[y];ll ret=;
while(fax!=fay){
if(dep[fax]<dep[fay]){
swap(fax,fay);swap(x,y);}
ret+=T.quary(,n,,num[fax],num[x]);
x=fa[fax];fax=top[x];}
if(dep[x]>dep[y])swap(x,y);
ret+=T.quary(,n,,num[x],num[y]);
return ret;
}
inline ll quary_tree(int x)
{
int ka=check(x);ll ret;
switch (ka){
case -:ret=T.seg[];break;
case :ret=T.quary(,n,,num[x],num[x]+size[x]-);break;
default:ret=T.seg[]-T.quary(,n,,num[ka],num[ka]+size[ka]-);break;
}
return ret;
}
int main()
{
n=read();int x,y,z,opt;root=;
memset(head,-,sizeof(head));
for(int i=;i<=n;i++)a[i]=read();
for(int i=;i<=n;i++){
x=read();add(x,i);add(i,x);}
dep[]=;dfs1();dfs2(,);
T.build(,n,);m=read();
for(int i=;i<=m;i++){
opt=read();
if(opt==){x=read();root=x;}
else if(opt==){
x=read();y=read();z=read();
modify_path(x,y,z);}
else if(opt==){
x=read();y=read();
modify_tree(x,y);}
else if(opt==){
x=read();y=read();
printf("%lld\n",quary_path(x,y));}
else {x=read();
printf("%lld\n",quary_tree(x));}}
return ;
}
LibreOJ #139 树链剖分 [树链剖分,线段树]的更多相关文章
- Qtree3题解(树链剖分(伪)+线段树+set)
外话:最近洛谷加了好多好题啊...原题入口 这题好像是SPOJ的题,挺不错的.看没有题解还是来一篇... 题意: 很明显吧.. 题解: 我的做法十分的暴力:树链剖分(伪)+线段树+\(set\)... ...
- Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树)
Luogu 2590 [ZJOI2008]树的统计 / HYSBZ 1036 [ZJOI2008]树的统计Count (树链剖分,LCA,线段树) Description 一棵树上有n个节点,编号分别 ...
- 【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树
题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) ...
- P3703-[SDOI2017]树点涂色【LCT,线段树】
正题 题目链接:https://www.luogu.com.cn/problem/P3703 题目大意 \(n\)个点的一棵树开始所有点有不同的颜色,\(m\)次操作 将根节点到\(x\)节点的路径上 ...
- Dynamic Rankings(树状数组套权值线段树)
Dynamic Rankings(树状数组套权值线段树) 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[ ...
- 「ZJOI2017」树状数组(二维线段树)
「ZJOI2017」树状数组(二维线段树) 吉老师的题目真是难想... 代码中求的是 \(\sum_{i=l-1}^{r-1}a_i\),而实际求的是 \(\sum_{i=l}^{r}a_i\),所以 ...
- BZOJ4860 BJOI2017 树的难题 点分治、线段树合并
传送门 只会线段树……关于单调队列的解法可以去看“重建计划”一题. 看到路径长度$\in [L,R]$考虑点分治.可以知道,在当前分治中心向其他点的路径中,始边(也就是分治中心到对应子树的根的那一条边 ...
- BZOJ2141排队——树状数组套权值线段树(带修改的主席树)
题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家 乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别 ...
- luogu3380/bzoj3196 二逼平衡树 (树状数组套权值线段树)
带修改区间K大值 这题有很多做法,我的做法是树状数组套权值线段树,修改查询的时候都是按着树状数组的规则找出那log(n)个线段树根,然后一起往下做 时空都是$O(nlog^2n)$的(如果离散化了的话 ...
- poj2528线段树解题报告,离散化+线段树
题目网址:http://poj.org/problem?id=2528 题意: n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=1 ...
随机推荐
- rocketmq单机搭建
RocketMQ 是alibaba开源的消息队列. 本文使用的是开源版本v3.18 系统: centos6.x最小化安装 需要用到的软件包: jdk-7u67-linux-x64.tar.gz ali ...
- Android 百度定位SDKv4.2及6.0_百度定位实例_安卓定位实例
介绍 由于项目需要.前几天一直在研究百度定位的功能.通过不断的实践终于有结果了.不愿意独享 现在我把我的研究成果和大家分享一下.其实百度的 API 已经相当不错了 这之所以要写出来.一是自己做一个笔记 ...
- 2017 济南综合班 Day 3
T1 黑化 题意: 求一个字符串是否可能包含另一个字符串 字符串中的?可以匹配任意字母 可能输出 God bless You! 一定不可能 输出 Game Over! 计算fail数组时,fail数 ...
- MySQL 5.7 跟踪优化器
Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 5Server version ...
- gradle web项目启动报错: java.lang.ClassNotFoundException: org.springframework.web.util.IntrospectorCleanupListener
严重: Error configuring application listener of class org.springframework.web.util.IntrospectorCleanup ...
- 【BZOJ】1578: [Usaco2009 Feb]Stock Market 股票市场
[题意]给定s个股票和d天,给出价格矩阵s*d,每天可以买入或卖出整数倍股票,初始资金m,求最大利益.m<=200000,s<=50,d<=10. [算法]完全背包 [题解]关键在于 ...
- bootstrap框架的搭建
bootstrap框架 Bootstrap,来自 Twitter,是目前最受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快 ...
- 微信小程序滑动选择器
实现微信小程序滑动选择效果 在wxml文件中,用一个picker标签代表选择器,bindchange是用户点击确定后触发的函数,index是picker自带的参数,用户点击确定后,bindchange ...
- H5特性 MutationObserver 监听元素 动态改变iframe高度
这些代码要写在iframe页中执行 <script type="text/javascript"> $(function () { // Firefox和Chrome早 ...
- 阅读关于DuReader:百度大规模的中文机器阅读理解数据集
很久之前就得到了百度机器阅读理解关于数据集的这篇文章,今天才进行总结!.... 论文地址:https://arxiv.org/abs/1711.05073 自然语言处理是人工智能皇冠上的明珠,而机器阅 ...