题目背景
SHOI2012 D2T3
题目描述
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行,每行是以下两种中的一种:
-
A u v d,表示将u到v的路径上的所有节点的果子数加上d;0 ≤ u,v <N,0 < d < 100000
-
Q u,表示询问以u为根的子树中的总果子数,注意是包括u本身的。
输出格式:
对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。
输入输出样例
输入样例#1: 复制
4 0 1 1 2 2 3 4 A 1 3 1 Q 0 Q 1 Q 2
输出样例#1: 复制
3 3 2
思维难度:NOIP+
代码难度:省选
算法:树链剖分
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int Maxn=100005;
ll fa[Maxn],sz[Maxn],son[Maxn],idx[Maxn],deep[Maxn],top[Maxn],h[Maxn],tcnt,cnt,root;
ll n,m;
struct node{
ll v,next;
}e[Maxn*2];
struct tree{
ll x,l,r,c;
}t[Maxn*4];
inline ll dfs1(ll u){
sz[u]=1;
ll heavy=0,maxn=0;
for(ll i=h[u];i;i=e[i].next){
ll v=e[i].v;
deep[v]=deep[u]+1;
fa[v]=u;
ll tmp=dfs1(v);
if(maxn<tmp){
maxn=tmp;
heavy=v;
}
sz[u]+=tmp;
}
son[u]=heavy;
return sz[u];
}
inline void dfs2(ll u){
idx[u]=++tcnt;
if(!son[u])return;
top[son[u]]=top[u];dfs2(son[u]);
for(ll i=h[u];i;i=e[i].next){
ll v=e[i].v;
if(son[u]==v)continue;
top[v]=v;
dfs2(v);
}
}
inline ll lson(ll rt){
return rt<<1;
}
inline ll rson(ll rt){
return rt<<1|1;
}
inline void pushup(ll rt){
t[rt].x=t[lson(rt)].x+t[rson(rt)].x;
}
inline void build(ll l,ll r,ll rt){
t[rt].l=l;t[rt].r=r;
if(l==r)return;
ll mid=l+r>>1;
build(l,mid,lson(rt));
build(mid+1,r,rson(rt));
}
inline void pushdown(ll rt){
if(t[rt].l==t[rt].r)return;
if(t[rt].c==0)return;
t[lson(rt)].c+=t[rt].c;
t[rson(rt)].c+=t[rt].c;
t[lson(rt)].x+=t[rt].c*(t[lson(rt)].r-t[lson(rt)].l+1);
t[rson(rt)].x+=t[rt].c*(t[rson(rt)].r-t[rson(rt)].l+1);
t[rt].c=0;
}
inline void update(ll l,ll r,ll x,ll rt){
if(t[rt].l>=l&&t[rt].r<=r){
t[rt].x+=x*(t[rt].r-t[rt].l+1);
t[rt].c+=x;
return;
}
pushdown(rt);
ll mid=t[rt].l+t[rt].r>>1;
if(l<=mid){
update(l,r,x,lson(rt));
}
if(r>mid){
update(l,r,x,rson(rt));
}
pushup(rt);
}
inline ll query(ll l,ll r,ll rt){
if(t[rt].l>=l&&t[rt].r<=r){
return t[rt].x;
}
pushdown(rt);
ll mid=t[rt].l+t[rt].r>>1,ans=0;
if(l<=mid){
ans+=query(l,r,lson(rt));
}
if(r>mid){
ans+=query(l,r,rson(rt));
}
return ans;
}
inline void Tupdate(ll x,ll y,ll val){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
update(idx[top[x]],idx[x],val,1);
x=fa[top[x]];
}
if(idx[x]>idx[y])swap(x,y);update(idx[x],idx[y],val,1);
}
inline char getc(){
char c=getchar();
while(c!='A'&&c!='Q')c=getchar();
return c;
}
inline ll read(){
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
inline void add(ll u,ll v){
cnt++;
e[cnt].v=v;
e[cnt].next=h[u];
h[u]=cnt;
}
int main(){
int u,v,w;char inc;n=read();
for(int i=1;i<=n-1;i++){
u=read();v=read();
add(u,v);
}
dfs1(root);dfs2(root);build(1,n,1);
m=read();
for(int i=1;i<=m;i++){
inc=getc();u=read();
if(inc=='A'){
v=read();w=read();
Tupdate(u,v,w);
}
else{
printf("%lld\n",query(idx[u],idx[u]+sz[u]-1,1));
}
}
return 0;
}