4034: [HAOI2015]T2
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 921 Solved: 313
[ Submit][ Status][ Discuss]
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
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
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。
//bzoj4034 单点更新和子树更新求区间
//操作 1 :把某个节点 x 的点权增加 a 。
//操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
//操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf -0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
const int maxn=101010;
int tot,p,v,L,R;
vector<int>G[maxn];
int siz[maxn],son[maxn],fa[maxn],deep[maxn],top[maxn],id[maxn],pre[maxn];
ll a[maxn];
ll addv[4*maxn];
ll sumv[4*maxn];
void init(int n){
tot=0;
for(int i=1;i<=n;i++)
G[i].clear();
mem0(addv);
mem0(sumv);
mem0(pre);
}
void dfs1(int u,int dep){
deep[u]=dep;
siz[u]=1,son[u]=0;
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v==fa[u])
continue;
fa[v]=u;
dfs1(v,dep+1);
if(siz[son[u]]<siz[v]){
son[u]=v;
}
siz[u]+=siz[v];
}
}
void dfs2(int u,int tp){
top[u]=tp;
id[u]=++tot;
pre[u]=id[u];
if(son[u]!=0){ //这里要注意也要更新pre[u]啊,坑了一个小时
dfs2(son[u],tp);
pre[u]=max(pre[u],pre[son[u]]);
}
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(son[u]==v||v==fa[u])
continue;
dfs2(v,v);
pre[u]=max(pre[u],pre[v]);
}
}
void pushup(int rt){
sumv[rt]=sumv[rt<<1]+sumv[rt<<1|1];
}
void build(int l,int r,int rt){
sumv[rt]=0;
if(l==r)
return ;
int m=(l+r)>>1;
build(lson);
build(rson);
}
void pushdown(int rt,int l){
if(addv[rt]!=0){
addv[rt<<1]+=addv[rt];
addv[rt<<1|1]+=addv[rt];
sumv[rt<<1]+=addv[rt]*(l-(l>>1));
sumv[rt<<1|1]+=addv[rt]*(l>>1);
addv[rt]=0;
}
}
void update1(int l,int r,int rt){
if(l==r){
sumv[rt]+=v;
return ;
}
int m=(l+r)>>1;
pushdown(rt,r-l+1);
if(p<=m)
update1(lson);
else
update1(rson);
pushup(rt);
}
void update2(int l,int r,int rt){
if(L<=l&&R>=r){
addv[rt]+=v;
sumv[rt]+=(ll)(r-l+1)*v;
return ;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
update2(lson);
if(R>m)
update2(rson);
pushup(rt);
}
ll query(int l,int r,int rt){
ll ret=0;
if(L<=l&&R>=r){
return sumv[rt];
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
ret+=query(lson);
if(R>m)
ret+=query(rson);
return ret;
}
ll Query(int u,int v){
ll ret=0;
int f1=top[u],f2=top[v];
while(f1!=f2){
if(deep[f1]<deep[f2]){
swap(f1,f2);
swap(u,v);
}
L=id[f1],R=id[u];
ret+=query(1,tot,1);
u=fa[f1];
f1=top[u];
}
if(deep[u]>deep[v]){
swap(f1,f2);
swap(u,v);
}
L=id[u],R=id[v];
ret+=query(1,tot,1);
return ret;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
init(n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
int u;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0);
build(1,tot,1);
for(int i=1;i<=n;i++){
p=id[i],v=a[i];
update1(1,tot,1);
}
int k;
for(int i=1;i<=m;i++){
scanf("%d",&k);
if(k==1){
scanf("%d%d",&u,&v);
p=id[u];
update1(1,tot,1);
}
if(k==2){
scanf("%d%d",&u,&v);
L=id[u],R=pre[u];
update2(1,tot,1);
}
if(k==3){
scanf("%d",&u);
printf("%lld\n",Query(u,1));
}
}
}
return 0;
}