题面

Description

有一棵点数为N的树,以点1为根,且树点有边权。然后有M个操作,分为三种:

操作1:把某个节点x的点权增加a。

操作2:把某个节点x为根的子树中所有点的点权都增加a。

操作3:询问某个节点x到根的路径中所有点的点权和。

Input

第一行两个整数N,M,表示点数和操作数。

接下来一行N个整数,表示树中节点的初始权值。

接下来N-1行每行两个正整数fr,to,表示该树中存在一条边(fr,to)。

再接下来M行,每行分别表示一次操作。其中第一个数表示该操作的种类(1~3),之后接这个操作的参数(x或者x a)。

Output

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

Sample Input

5 5

1 2 3 4 5

1 2

1 4

2 3

2 5

3 3

1 2 1

3 5

2 1 2

3 3

Sample Output

6

9

13

Hint

数据范围:

对于30%的数据,N,M<=1000。

对于50%的数据,N,M<=100000且数据随机。

对于100%的数据,N,M<=100000,且所有输入数据的绝对值都不会超过10^6。

题解

依旧是很显然的树链剖分,要用longlong存答案

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX 101000
#define lson (now<<1)
#define rson ((now<<1)|1)
inline int read()
{
register int x=0,t=1;
register char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-'){t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*t;
}
struct Line
{
int v,next;
}e[MAX*2];
struct Node
{
long long v,lazy;
}c[MAX*5];
int h[MAX],cnt=1,tim,V[MAX];
int dfn[MAX],low[MAX],f[MAX],hson[MAX],line[MAX],size[MAX],top[MAX];
int N,Q,dep[MAX];
inline void Add(int u,int v)
{
e[cnt]=(Line){v,h[u]};
h[u]=cnt++;
}
void DFS1(int u,int ff)
{
size[u]=1;f[u]=ff;hson[u]=0;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==ff)continue;
DFS1(v,u);
if(size[v]>size[hson[u]])hson[u]=v;
size[u]+=size[v];
}
}
void DFS2(int u,int tp)
{
top[u]=tp;dfn[u]=++tim;line[tim]=u;
if(hson[u])DFS2(hson[u],tp);
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==f[u]||v==hson[u])continue;
DFS2(v,v);
}
low[u]=tim;
}
void Build(int now,int l,int r)
{
if(l==r){c[now].v=V[line[l]];return;}
int mid=(l+r)>>1;
Build(lson,l,mid);Build(rson,mid+1,r);
c[now].v=c[lson].v+c[rson].v;
}
void pushdown(int now,int l,int r)
{
c[now].v+=1LL*(r-l+1)*c[now].lazy;
c[lson].lazy+=c[now].lazy;
c[rson].lazy+=c[now].lazy;
c[now].lazy=0;
}
void update(int now,int l,int r,int al,int ar,int w)
{
if(l==al&&r==ar){c[now].lazy+=w;return;}
int mid=(l+r)>>1;
c[now].v+=1LL*(ar-al+1)*w;
if(ar<=mid)update(lson,l,mid,al,ar,w);
else if(al>mid)update(rson,mid+1,r,al,ar,w);
else {update(lson,l,mid,al,mid,w);update(rson,mid+1,r,mid+1,ar,w);}
}
long long Query(int now,int l,int r,int al,int ar)
{
pushdown(now,l,r);
if(l==al&&r==ar)return c[now].v;
int mid=(l+r)>>1;
if(ar<=mid)return Query(lson,l,mid,al,ar);
if(al>mid)return Query(rson,mid+1,r,al,ar);
return Query(lson,l,mid,al,mid)+Query(rson,mid+1,r,mid+1,ar);
}
long long Answer(int u)
{
int v=1,tp1=top[u],tp2=top[v];
long long ans=0;
while(tp1!=tp2)
{
if(dep[tp1]<dep[tp2])
{
swap(tp1,tp2);
swap(u,v);
}
ans+=Query(1,1,N,dfn[tp1],dfn[u]);
u=f[tp1];tp1=top[u];
}
if(dep[u]<dep[v])swap(u,v);
ans+=Query(1,1,N,dfn[v],dfn[u]);
return ans;
}
int main()
{
N=read();Q=read();
for(int i=1;i<=N;++i)V[i]=read();
for(int i=1;i<N;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
DFS1(1,0);DFS2(1,1);
Build(1,1,N);
while(Q--)
{
int kk=read();
if(kk==1)
{
int a=read(),b=read();
update(1,1,N,dfn[a],dfn[a],b);
}
if(kk==2)
{
int a=read(),b=read();
update(1,1,N,dfn[a],low[a],b);
}
if(kk==3)
{
int a=read();
printf("%lld\n",Answer(a));
}
}
return 0;
}

【HAOI2015】树上操作(树链剖分)的更多相关文章

  1. bzoj4034[HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 6163  Solved: 2025[Submit][Stat ...

  2. bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Stat ...

  3. 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树

    [BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...

  4. BZOJ4034 [HAOI2015]树上操作 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4034 题意概括 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三 ...

  5. P3178 [HAOI2015]树上操作 树链剖分

    这个题就是一道树链剖分的裸题,但是需要有一个魔性操作___编号数组需要开longlong!!!震惊!真的神奇. 题干: 题目描述 有一棵点数为 N 的树,以点 为根,且树点有边权.然后有 M 个操作, ...

  6. BZOJ4034[HAOI2015]树上操作——树链剖分+线段树

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...

  7. bzoj 4034: [HAOI2015]树上操作——树链剖分

    Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...

  8. BZOJ 4034[HAOI2015]树上操作(树链剖分)

    Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点 ...

  9. bzoj4034 [HAOI2015]树上操作——树链剖分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4034 树剖裸题: 一定要注意 long long !!! update 的时候别忘了 pus ...

  10. [HAOI2015]树上操作-树链剖分

    #include<bits/stdc++.h> using namespace std; const int maxn = 1e6+5; #define mid ((l+r)>> ...

随机推荐

  1. 基于Java的WebSocket推送

    WebSocket的主动推送 关于消息推送,现在的解决方案如轮询.长连接或者短连接,当然还有其他的一些技术框架,有的是客户端直接去服务端拿数据. 其实推送推送主要讲的是一个推的概念,WebSocket ...

  2. centos7时间同步

    用ntpdate从时间服务器更新时间 1.如果你的linux系统根本没有ntpdate这个命令 yum install -y ntp 2.安装完了之后,你不要做什么配置,也不需要,直接测试一下 [ro ...

  3. 【转】egametang框架简介

    讨论QQ群 : 474643097 1.可用VS单步调试的分布式服务端,N变1 一般来说,分布式服务端要启动很多进程,一旦进程多了,单步调试就变得非常困难,导致服务端开发基本上靠打log来查找问题.平 ...

  4. 通过读取配置文件,启动mongodb

    在实际的项目中,经常利用mongodb数据库做缓存,mongodb的并发性比较高,所以对于快速存储.读取信息有很多优点.在项目中对于第一次的数据请求会直接访问数据库,而对于获得的信息通常都会在此时刻存 ...

  5. js “top、clientTop、scrollTop、offsetTop…”

    当要做一些与位置相关的插件或效果的时候,像top.clientTop.scrollTop.offsetTop.scrollHeight.clientHeight.offsetParent...看到这么 ...

  6. pro asp.net mvc 5笔记

    1.Ninject条件绑定方法When(predicate)WhenClassHas<T>()WhenInj ectedInto<T>()例: kernel.Bind<I ...

  7. 如何写出测不出bug的测试用例

    我们写测试用例的目的是为了能够整理思路,把要测试的地方列出来,做为知识的积淀,用例可以交给其他测试人员执行,或者是跟需求提出者进行讨论,对用例进行补充和修改. 理论上用例写的越多,越容易发现bug.但 ...

  8. HDU - 2187 贪心

    思路:  按照单价升序排序,依次买就行. AC代码 #include <cstdio> #include <cmath> #include <algorithm> ...

  9. ThinkPad W500 清灰记录

    转载请注明出处:HateMath归来(http://www.cnblogs.com/hatemath/) 看型号就知道,这是一台英雄迟暮型的老电脑.到了夏天,启动后啥事不做,通风口都烫手.心情好,一时 ...

  10. 源码编译安装Apache-附一键部署脚本

    1.进入apache官网https://www.apache.org/,点击Download 2.如图选择 3.选择httpd 4.下载两个包,2.2为CentOS6使用,2.4为CentOS7使用 ...