【题目描述】
Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。
这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u] < u。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即0个果子)。
不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:
Add u v d
表示将点u和v之间的路径上的所有节点的果子个数都加上d。
接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:
Query u
表示当前果树中,以点u为根的子树中,总共有多少个果子?
【输入格式】
第一行一个正整数N (1 ≤ N ≤ 100000),表示果树的节点总数,节点以0,1,…,N − 1标号,0一定代表根节点。
接下来N − 1行,每行两个整数a,b (0 ≤ a < b < N),表示a是b的父亲。
接下来是一个正整数Q(1 ≤ ? ≤ 100000),表示共有Q次操作。
后面跟着Q行,表示各个询问。
【输出格式】
对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。
【样例输入】
4
0 1
1 2
2 3
4
A 1 3 1
Q 0
Q 1
Q 2
【样例输出】
3
3
2
【题意分析】
树链剖分模板题,题目前面一堆废话,但是注意节点从0开始。
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAX 200000
using namespace std;
typedef long long ll;
struct Front_Link_Star{
ll next,to;
}edge[MAX];
ll tree[MAX << 2],lazy[MAX << 2],res;
ll top[MAX],head[MAX],son[MAX],depth[MAX],father[MAX];
ll size[MAX],id[MAX],n,m,cnt,dfn;
inline void Add_Edge(ll u,ll v){
edge[++cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
}
inline void push_down(ll now,ll tl,ll tr){
ll mid=(tl+tr) >> 1;
tree[now << 1]+=lazy[now]*(mid-tl+1);
tree[now << 1|1]+=lazy[now]*(tr-mid);
lazy[now << 1]+=lazy[now];
lazy[now << 1|1]+=lazy[now];
lazy[now]=0;
}
inline void update(ll now,ll tl,ll tr,ll left,ll right,ll change){
if (right<tl||tr<left)return;
if (left<=tl&&tr<=right){
tree[now]+=change*(tr-tl+1);
lazy[now]+=change;
return;
}
if (lazy[now])push_down(now,tl,tr);
ll mid=(tl+tr) >> 1;
update(now << 1,tl,mid,left,right,change);
update(now << 1|1,mid+1,tr,left,right,change);
tree[now]=tree[now << 1]+tree[now << 1|1];
}
inline void query(ll now,ll tl,ll tr,ll left,ll right){
if (right<tl||tr<left)return;
if (left<=tl&&tr<=right){
res+=tree[now];
return;
}
if (lazy[now])push_down(now,tl,tr);
ll mid=(tl+tr) >> 1;
query(now << 1,tl,mid,left,right);
query(now << 1|1,mid+1,tr,left,right);
}
inline void Modify_Range(ll x,ll y,ll z){
while (top[x]!=top[y]){
if (depth[top[x]]<depth[top[y]])swap(x,y);
update(1,1,n,id[top[x]],id[x],z);
x=father[top[x]];
}
if (depth[x]>depth[y])swap(x,y);
update(1,1,n,id[x],id[y],z);
}
inline ll Query_Tree(ll x){
res=0;
query(1,1,n,id[x],id[x]+size[x]-1);
return res;
}
inline void DFS1(ll now,ll fa,ll d){
father[now]=fa;
depth[now]=d;
size[now]=1;
ll maxson=-1;
for (register int i=head[now];i;i=edge[i].next){
ll v=edge[i].to;
if (v==fa)continue;
DFS1(v,now,d+1);
size[now]+=size[v];
if (maxson<size[v]){
maxson=size[v];
son[now]=v;
}
}
}
inline void DFS2(ll now,ll top_heavy){
top[now]=top_heavy;
id[now]=++dfn;
if (!son[now])return;
DFS2(son[now],top_heavy);
for (register int i=head[now];i;i=edge[i].next){
ll v=edge[i].to;
if (v!=father[now]&&v!=son[now])DFS2(v,v);
}
}
int main(){
scanf("%lld",&n);
for (register int i=1;i<n;i++){
ll x,y;
scanf("%lld%lld",&x,&y);
x++;y++;
Add_Edge(x,y);
Add_Edge(y,x);
}
DFS1(1,0,1);
DFS2(1,1);
scanf("%lld",&m);
while (m--){
char ch[4];
ll x,y,z;
scanf("%s",&ch);
if (ch[0]=='A'){
scanf("%lld%lld%lld",&x,&y,&z);
Modify_Range(x+1,y+1,z);
}
if (ch[0]=='Q'){
scanf("%lld",&x);
printf("%lld\n",Query_Tree(x+1));
}
}
return 0;
}