[HAOI2015]树上操作(树链剖分)
Description
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:
- 操作 1 :把某个节点 x 的点权增加 a 。
- 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
- 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
输入格式
第一行包含两个整数 N, M 。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
输出格式
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Solution
操作 1:线段树中点dfn[x]加a;
操作 2:由树链剖分遍历的顺序可知任何一棵子树中节点的dfs序<=子树的根的dfs序,
且最大的dfs序=子树的根的dfs序+子树的大小-1,于是可以直接在线段树上操作;
操作 3:简化版树剖求和模板
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
using namespace std;
const int N=1e5+;
struct node
{
int l,r,lc,rc;
long long sum,delay;
}f[N*];
int n,u,v,m,deep[N],tot,si[N],top[N],d[N],t,
fa[N],dfn[N],cnt,rt,son[N],re[N],opt,x;
long long a;
char s[];
vector <int> link[N];
void dfs1(int u,int f)
{
si[u]=,fa[u]=f,deep[u]=deep[f]+;
int size=link[u].size();
for(int i=;i<size;i++)
{
int v=link[u][i];
if(v!=f)
{
dfs1(v,u);
si[u]+=si[v];
if(son[u]== || si[son[u]]<si[v]) son[u]=v;
}
}
}
void dfs2(int u,int f)
{
dfn[u]=++tot,re[tot]=u;
if(son[u]!=)
{
top[son[u]]=top[u],dfs2(son[u],u);
int size=link[u].size();
for(int i=;i<size;i++)
{
int v=link[u][i];
if(v!=f && v!=son[u])
top[v]=v,dfs2(v,u);
}
}
}
long long gel(int g)
{
return f[g].r-f[g].l+;
}
void push_up(int g)
{
int lc=f[g].lc,rc=f[g].rc;
if(lc==) return ;
f[g].sum=f[lc].sum+f[rc].sum+gel(g)*f[g].delay;
}
void push_down(int g)
{
int lc=f[g].lc,rc=f[g].rc;
if(lc== || f[g].delay==) return ;
f[lc].delay+=f[g].delay,f[rc].delay+=f[g].delay;
f[lc].sum+=gel(lc)*f[g].delay,f[rc].sum+=gel(rc)*f[g].delay;
f[g].delay=;
}
void build(int &g,int l,int r)
{
g=++cnt;
f[g].l=l,f[g].r=r;
if(l==r)
{
f[g].sum=d[re[l]];
return ;
}
int mid=(l+r)>>;
build(f[g].lc,l,mid);
build(f[g].rc,mid+,r);
push_up(g);
}
void add(int g,int l,int r,int k)
{
if(f[g].l>=l && f[g].r<=r)
f[g].sum+=gel(g)*k,f[g].delay+=k;
else
{
int mid=(f[g].l+f[g].r)/;
if(r<=mid) add(f[g].lc,l,r,k);
else if(l>mid) add(f[g].rc,l,r,k);
else add(f[g].lc,l,mid,k),add(f[g].rc,mid+,r,k);
push_up(g);
}
}
long long get(int g,int l,int r)
{
if(f[g].l>=l && f[g].r<=r)
return f[g].sum;
else
{
push_down(g);
int mid=(f[g].l+f[g].r)/;
if(r<=mid) return get(f[g].lc,l,r);
else if(l>mid) return get(f[g].rc,l,r);
else return get(f[g].lc,l,mid)+get(f[g].rc,mid+,r);
}
}
long long Get(int x)
{
long long sum=;
while(x!=)
{
sum+=get(rt,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
return sum;
}
//操作 1 :把某个节点 x 的点权增加 a 。
//操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
//操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%d",&d[i]);
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
link[u].push_back(v);
link[v].push_back(u);
}
dfs1(,);
top[]=,dfs2(,);
build(rt,,tot);
while(m--)
{
scanf("%d%d",&opt,&x);
if(opt==) printf("%lld\n",Get(x));
else
{
scanf("%lld",&a);
if(a!=)
{
if(opt==) add(rt,dfn[x],dfn[x],a);
else if(opt==) add(rt,dfn[x],dfn[x]+si[x]-,a);
}
}
}
return ;
}
[HAOI2015]树上操作(树链剖分)的更多相关文章
- bzoj4034[HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6163 Solved: 2025[Submit][Stat ...
- bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4352 Solved: 1387[Submit][Stat ...
- 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树
[BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...
- BZOJ4034 [HAOI2015]树上操作 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4034 题意概括 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三 ...
- P3178 [HAOI2015]树上操作 树链剖分
这个题就是一道树链剖分的裸题,但是需要有一个魔性操作___编号数组需要开longlong!!!震惊!真的神奇. 题干: 题目描述 有一棵点数为 N 的树,以点 为根,且树点有边权.然后有 M 个操作, ...
- BZOJ4034[HAOI2015]树上操作——树链剖分+线段树
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...
- bzoj 4034: [HAOI2015]树上操作——树链剖分
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...
- BZOJ 4034[HAOI2015]树上操作(树链剖分)
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点 ...
- bzoj4034 [HAOI2015]树上操作——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4034 树剖裸题: 一定要注意 long long !!! update 的时候别忘了 pus ...
- [HAOI2015]树上操作-树链剖分
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6+5; #define mid ((l+r)>> ...
随机推荐
- codeforces 1183H 动态规划
codeforces 1183H 动态规划 传送门:https://codeforces.com/contest/1183/problem/H 题意: 给你一串长度为n的字符串,你需要寻找出他的最长的 ...
- Mac Tab自动补全键
最近入手一个Mac(Mac 2019版本),在使用终端时,发现不能使用Tab键自动补全代码,网络搜寻下,发现这里有个方法,记录下,免得自己忘记: 1 / 首先找到这个图标 2 / 输入命令 nano ...
- Analysis of Two-Channel Generalized Sidelobe Canceller (GSC) With Post-Filtering
作者:凌逆战 地址:https://www.cnblogs.com/LXP-Never/p/12071748.html 题目:带后置滤波的双通道广义旁瓣相消器(GSC)的分析 作者:Israel Co ...
- MySQL 核心三剑客 —— 索引、锁、事务
一.常见存储引擎 1.1 InnoDB InnoDB 是 MySQL 5.5 之后默认的存储引擎,它具有高可靠.高性能的特点,主要具备以下优势: DML 操作完全遵循 ACID 模型,支持事务,支持崩 ...
- 「USACO11NOV」牛的障碍Cow Steeplechase 解题报告
题面 横的,竖的线短段,求最多能取几条没有相交的线段? 思路 学过网络流的童鞋在哪里? 是时候重整网络流雄风了! 好吧,废话不多说 这是一道最小割的题目 怎么想呢? 要取最多,那反过来不就是不能取的要 ...
- 1091 N-自守数 (15 分)C语言
如果某个数 K 的平方乘以 N 以后,结果的末尾几位数等于 K,那么就称这个数为"N-自守数".例如 3×92^2 =25392,而 25392 的末尾两位正好是 92,所以 ...
- 深入浅出 JVM 系列(一)什么是 JVM?它处于什么位置?
.katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...
- Scala实践3
一.函数式对象 1.1 rational类的规格和创建 Rational类来源于有理数(rational number),来表示n(分子)/d(分母)的数字,同时对有理数的运算(加减乘除)建模,还具 ...
- php5.6.39 源码安装
1 安装依赖库 yum install -y autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel li ...
- Spring Boot2 系列教程 (十八) | 整合 MongoDB
微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 如题,今天介绍下 SpringBoot 是如何整合 MongoDB 的. MongoDB 简介 MongoDB 是由 C++ ...