题目描述
有一棵点数为 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 ) 。
输出格式
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
输入输出样例
输入 #1
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
6
9
13
说明/提示
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10610^6106 。
解释:树链剖分题,查找以X为根的子树,其实就是查找[dfn[x],dfn[x]+sz[x]−1].[dfn[x],dfn[x]+sz[x]-1].[dfn[x],dfn[x]+sz[x]−1].,其中dfn[x]dfn[x]dfn[x]为dfsdfsdfs序,sz[x]sz[x]sz[x]表示以X为根的节点个数。其他都是裸模板
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
inline char nc() {
static char buf[2000000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,2000000,stdin),p1==p2)?EOF:*p1++;
}
template <class Tp> inline void read(register Tp &s) {
s=0;
register bool neg=0;
register char c=nc();
for(;c<'0'||c>'9';c=nc()) neg|=(c=='-');
for(;c>='0'&&c<='9';s=s*10+(c^48),c=nc());
s=(neg?-s:s);
}
const ll N=200000,M=200000;
ll n,idx,dfn[N],seq[N],U[N],V[N],W[N],val[N],fa[N],dep[N],top[N],sz[N],hvy[N];
ll lazy[N]={0};
ll tot,lnk[N],ter[M],nxt[M],seg[N<<2];
void add(ll u,ll v) {
ter[++tot]=v,nxt[tot]=lnk[u],lnk[u]=tot;
}
void dfs1(ll u,ll f) {
fa[u]=f,dep[u]=dep[f]+1,sz[u]=1,hvy[u]=top[u]=0;
for(ll i=lnk[u];i;i=nxt[i]) {
ll v=ter[i];
if(v==f) continue;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[hvy[u]]<sz[v]) hvy[u]=v;
}
}
void dfs2(ll u,ll tp){
dfn[u]=++idx,seq[idx]=u,top[u]=tp;
if(!hvy[u]) return;
dfs2(hvy[u],tp);
for(ll i=lnk[u];i;i=nxt[i]) {
ll v=ter[i];
if(v==fa[u]||v==hvy[u]) continue;
dfs2(v,v);
}
}
void pushup(ll rt) {
seg[rt]=seg[lson]+seg[rson];
}
void pushdown(ll rt,ll l,ll r){
ll mid=(l+r)/2;
seg[lson]+=lazy[rt]*(mid-l+1);
seg[rson]+=lazy[rt]*(r-mid);
lazy[lson]+=lazy[rt];
lazy[rson]+=lazy[rt];
lazy[rt]=0;
}
void build(ll rt,ll l,ll r) {
if(l==r) {
seg[rt]=val[seq[l]];
return;
}
ll mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
void modify(ll l,ll r,ll rt,ll L,ll R,ll val) {
pushdown(rt,L,R);
if(l<=L&&R<=r){
seg[rt]+=val*(R-L+1);
lazy[rt]+=val;
return;
}
ll mid=(L+R)>>1;
if(l<=mid) modify(l,r,lson,L,mid,val);
if(r>mid) modify(l,r,rson,mid+1,R,val);
pushup(rt);
}
ll query(ll x,ll y,ll rt,ll l,ll r){
pushdown(rt,l,r);
if(x>y) return 0;
if(x<=l&&r<=y) return seg[rt];
ll mid=(l+r)>>1,res=0;
if(x<=mid) res+=query(x,y,lson,l,mid);
if(mid<y) res+=query(x,y,rson,mid+1,r);
return res;
}
ll chainQuery(ll u,ll v){
ll res=0;
for(ll fu=top[u],fv=top[v];fu^fv;u=fa[fu],fu=top[u]){
if(dep[fu]<dep[fv]) swap(u,v),swap(fu,fv);
res+=query(dfn[fu],dfn[u],1,1,n);
}
if(dep[u]>dep[v]) swap(u,v);
res+=query(dfn[u],dfn[v],1,1,n);
return res;
}ll m=0;
int main(){
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++) scanf("%lld",&val[i]);
for(ll i=1;i<n;++i){
ll u,v;
scanf("%lld%lld",&u,&v);
add(u,v),add(v,u);
}
dfs1(1,0),dfs2(1,1);
build(1,1,n);
while(m--){
ll cmd;scanf("%lld",&cmd);
if(cmd==1){
ll x,a;scanf("%lld%lld",&x,&a);
modify(dfn[x],dfn[x],1,1,n,a);
}else if(cmd==2){
ll x,a;scanf("%lld%lld",&x,&a);
modify(dfn[x],dfn[x]+sz[x]-1,1,1,n,a);
}else{
ll x=0;scanf("%lld",&x);
printf("%lld\n",chainQuery(1,x));
}
}
return 0;
}