4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6487 Solved: 2161
[ 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 。
思路&&分析
这题三个操作分别是给一个点加值,一个是给一个点的子树加值,一个是查询一条根到该点的路径的权值和,那么很显然,可以直接上树剖,然后用线段树维护这些值就好了..(P.S. 要开longlong)
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
template<class T>inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=f;
}
#define rd(x) read(x)
#define r2(x,y) rd(x),rd(y)
#define r3(x,y,z) r2(x,y),rd(z)
#define r4(x,y,z,o) r2(x,y),r2(z,o)
#define ls o<<1
#define rs o<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
const int maxn=200010;
int n,q,v[maxn],nw[maxn],id[maxn],tp[maxn],fa[maxn],son[maxn],dep[maxn],sz[maxn],dfs_clock;
vector<int>G[maxn];
ll sum[maxn<<2],lazy[maxn<<2];
inline void pushup(int o){sum[o]=sum[ls]+sum[rs];}
inline void pushdown(int o,int l,int r) {
if(lazy[o]) {
int mid=(l+r)>>1;
sum[ls]+=lazy[o]*(mid-l+1);
sum[rs]+=lazy[o]*(r-mid);
lazy[ls]+=lazy[o];
lazy[rs]+=lazy[o];
lazy[o]=0;
}
}
inline void build(int o,int l,int r) {
if(l==r) {
sum[o]=nw[l];
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(o);
}
inline void update(int o,int l,int r,int ql,int qr,ll add) {
pushdown(o,l,r);
if(l==ql&&r==qr) {
sum[o]+=add*(r-l+1);
lazy[o]+=add;
return;
}
int mid=(l+r)>>1;
if(mid>=qr)
update(ls,l,mid,ql,qr,add);
else if(mid<ql)
update(rs,mid+1,r,ql,qr,add);
else {
update(ls,l,mid,ql,mid,add);
update(rs,mid+1,r,mid+1,qr,add);
}
pushup(o);
}
inline ll query(int o,int l,int r,int ql,int qr) {
pushdown(o,l,r);
if(l==ql&&r==qr)
return sum[o];
int mid=(l+r)>>1;
if(mid>=qr)
return query(ls,l,mid,ql,qr);
else if(mid<ql)
return query(rs,mid+1,r,ql,qr);
else
return query(ls,l,mid,ql,mid)+query(rs,mid+1,r,mid+1,qr);
}
inline void dfs1(int u) {
sz[u]=1;
for(unsigned i=0;i<G[u].size();i++) {
int v=G[u][i];
if(v==fa[u])
continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
sz[u]+=sz[v];
if(!son[u]||sz[son[u]]<sz[v])
son[u]=v;
}
}
inline void dfs2(int u,int p) {
tp[u]=p;
id[u]=++dfs_clock;
nw[dfs_clock]=v[u];
if(!son[u])
return;
dfs2(son[u],p);
for(unsigned i=0;i<G[u].size();i++) {
int v=G[u][i];
if(v==fa[u]||v==son[u])
continue;
dfs2(v,v);
}
}
inline ll subqsum(int x,int y) {
ll ans=0;
while(tp[x]!=tp[y]) {
if(dep[tp[x]]<dep[tp[y]])
swap(x,y);
ans+=query(1,1,n,id[tp[x]],id[x]);
x=fa[tp[x]];
}
if(dep[x]>dep[y])
swap(x,y);
ans+=query(1,1,n,id[x],id[y]);
return ans;
}
signed main() {
rd(n);rd(q);
for(int i=1;i<=n;i++)
rd(v[i]);
for(int i=1,x,y;i<n;i++) {
r2(x,y);
G[x].push_back(y);
G[y].push_back(x);
}
fa[1]=-1;dep[1]=1;
dfs1(1);
dfs2(1,1);
build(1,1,n);
while(q--) {
int op,a;ll b;
r2(op,a);
if(op==1) {
rd(b);
update(1,1,n,id[a],id[a],b);
}
else if(op==2) {
rd(b);
update(1,1,n,id[a],id[a]+sz[a]-1,b);
}
else
printf("%lld\n",subqsum(1,a));
}
return 0;
}