题目背景
SHOI2012 D2T3
题目描述
Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。
这棵果树共有 N个节点,其中节点 0 是根节点,每个节点 u的父亲记为 fa[u],保证有 fa[u] < u 。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即 0 个果子)。
不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:A u v d
。表示将点 u和 v 之间的路径上的所有节点的果子个数都加上 d**。
接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:Q u
。表示当前果树中,以点 uu 为根的子树中,总共有多少个果子?
输入格式
第一行一个正整数 (N (1 leq N leq 100000)),表示果树的节点总数,节点以 (0,1,dots,N - 1) 标号,0 一定代表根节点。
接下来 N - 1 行,每行两个整数 (a,b (0 leq a < b < N)),表示 a 是 b 的父亲。
接下来是一个正整数 (Q(1 leq Q leq 100000)),表示共有 (Q) 次操作。
后面跟着 (Q) 行,每行是以下两种中的一种:
A u v d
,表示将 (u) 到 (v) 的路径上的所有节点的果子数加上 (d)。保证 (0 leq u,v < N,0 < d < 100000)Q u
,表示询问以 (u) 为根的子树中的总果子数,注意是包括 (u)本身的。
输出格式
对于所有的 Q
操作,依次输出询问的答案,每行一个。答案可能会超过 (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
思路
支持两个操作,链上修改,子树查询
树剖裸题,代码就在板子基础上,改改输入输出就行
代码
#include<bits/stdc++.h>
using namespace std;
const int N=200100;
typedef long long LL;
const int M=N*2;
int n,m;
int head[N],ver[N],ne[N],idx;
int w[N];
int id[N],nw[N],cnt;
int dep[N],sz[N],top[N],fa[N],son[N];
char ch[4];
struct node
{
int l,r;
LL add,sum;
} tr[N<<2];
void add(int u,int v)
{
ne[idx]=head[u];
ver[idx]=v;
head[u]=idx;
idx++;
}
void dfs1(int u,int father,int depth)
{
sz[u]=1;
fa[u]=father;
dep[u]=depth;
for(int i=head[u]; i!=-1; i=ne[i])
{
int j=ver[i];
if(j==father)continue;
dfs1(j,u,depth+1);
sz[u]+=sz[j];
if(sz[son[u]]<sz[j]) son[u]=j;//sz大小,
}
}
void dfs2(int u,int t) //t保存u所在当前重链的顶点是谁
{
id[u]=++cnt;//dfs序
nw[cnt]=w[u];
top[u]=t;
if(!son[u]) return;
dfs2(son[u],t);
for(int i=head[u]; i!=-1; i=ne[i])
{
int j=ver[i];
if(j==fa[u]||j==son[u])continue;
dfs2(j,j);
}
}
struct tree
{
inline void pushup(int p)
{
tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
}
inline void pushdown(int p)
{
if(tr[p].add)
{
tr[p<<1].sum+=(tr[p<<1].r-tr[p<<1].l+1)*tr[p].add;
tr[p<<1].add+=tr[p].add;
tr[p<<1|1].sum+=(tr[p<<1|1].r-tr[p<<1|1].l+1)*tr[p].add;
tr[p<<1|1].add+=tr[p].add;
tr[p].add=0;
}
}
void build(int p,int l,int r)
{
tr[p]= {l,r,0,nw[l]};
if(l==r) return;
int mid=(tr[p].l+tr[p].r)/2;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void update(int p,int l,int r,int k)
{
if(tr[p].l>=l&&tr[p].r<=r)
{
tr[p].sum+=(tr[p].r-tr[p].l+1)*k;
tr[p].add+=k;
return ;
}
pushdown(p);
int mid=tr[p].l+tr[p].r>>1;
if(l<=mid) update(p<<1,l,r,k);
if(r>mid) update(p<<1|1,l,r,k);
pushup(p);
}
LL query(int p,int l,int r)
{
if(tr[p].l>=l&&tr[p].r<=r)
{
return tr[p].sum;
}
pushdown(p);
int mid=tr[p].l+tr[p].r>>1;
LL ans=0;
if(l<=mid) ans+=query(p<<1,l,r);
if(r>mid) ans+=query(p<<1|1,l,r);
return ans;
}
} segment;
struct tre
{
void update_path(int u,int v,int k)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
segment.update(1,id[top[u]],id[u],k);
u=fa[top[u]];
}
if(dep[u]<dep[v])
swap(u,v);
segment.update(1,id[v],id[u],k);
}
LL query_path(int u,int v)
{
LL res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
res+=segment.query(1,id[top[u]],id[u]);
u=fa[top[u]];
}
if(dep[u]<dep[v])
swap(u,v);
res+=segment.query(1,id[v],id[u]);
return res;
}
void update_tree(int u,int k)
{
segment.update(1,id[u],id[u]+sz[u]-1,k);
}
LL query_tree(int u)
{
segment.query(1,id[u],id[u]+sz[u]-1);
}
} chain;
inline int read()
{
int x=0;
int f=1;
char ch;
ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10,x=x+ch-'0';
ch=getchar();
}
return x*f;
}
int main()
{
scanf("%d",&n);
memset(head,-1,sizeof(head));
for(int i=1; i<=n-1; i++)
{
int a,b;
a=read();
b=read();
a++;
b++;
add(a,b);
add(b,a);
}
dfs1(1,-1,1);
dfs2(1,1) ;
segment.build(1,1,n);
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
int t,u,v,k;
scanf("%s",ch+1);
if(ch[1]=='A')
{
scanf("%d%d%d",&u,&v,&k);
{
chain.update_path(u+1,v+1,k);
}
}
else
{
scanf("%d",&u);
printf("%lld
",chain.query_tree(u+1));
}
}
return 0;
}