题目:LOJ147.
题目大意:给定一棵 n n n个点的树,要求支持以下操作:
1.格式 1   a   x 1\,a\,x 1ax,表示将点 a a a的点权增加 x x x.
2.格式 2   a   x 2\,a\,x 2ax,表示将点 a a a的子树增加 x x x.
3.格式 3   a   b 3\,a\,b 3ab,表示查询链 ( a , b ) (a,b) (a,b)的点权和.
设操作数量为 m m m,则 1 ≤ n , m ≤ 1 0 6 1\leq n,m\leq 10^6 1≤n,m≤106.
同时维护两个修改貌似并不好搞,所以考虑分成修改点权+查询链和修改子树+查询链两个子问题.
子问题1:修改点权+查询链可以通过维护每个点到根这条链的点权和来实现.此时修改点权想到与修改子树,查询链相当于查询点权,然后通过树上差分实现查询任意链的点权和.
子问题2:修改子树+查询链仍然通过维护每个点 x x x到根这条链的点权和 v [ x ] v[x] v[x].设点 x x x深度为 d e p [ k ] dep[k] dep[k],那么点 x x x子树中,那么对子树 x x x增加 w w w会使得 v [ y ] v[y] v[y]增加 w ( d e p [ y ] − d e p [ x ] + 1 ) = w ∗ d e p [ y ] − w ( d e p [ x ] − 1 ) w(dep[y]-dep[x]+1)=w*dep[y]-w(dep[x]-1) w(dep[y]−dep[x]+1)=w∗dep[y]−w(dep[x]−1),发现 − w ( d e p [ x ] − 1 ) -w(dep[x]-1) −w(dep[x]−1)可以与子问题1一起维护, w ∗ d e p [ y ] w*dep[y] w∗dep[y]可以再维护一个树状数组来实现.
时间复杂度 O ( ( n + m ) log n ) O((n+m)\log n) O((n+m)logn).
代码如下:
#include
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000000;
int Ri(){
int x=0,y=1;
char c=getchar();
for (;c<'0'||c>'9';c=getchar()) if (c=='-') y=-1;
for (;c<='9'&&c>='0';c=getchar()) x=x*10+c-'0';
return x*y;
}
int n,m,v[N+9],rot;
struct side{
int y,next;
}e[N*2+9];
int lin[N+9],top;
void Ins(int x,int y){
e[++top].y=y;
e[top].next=lin[x];
lin[x]=top;
}
int ld[N+9],rd[N+9],ord[N+9],co;
struct node{
int fa,son,top,dep,siz;
}d[N+9];
void Dfs1(int k,int fa){
ord[++co]=k;ld[k]=co;
d[k].fa=fa;
d[k].dep=d[fa].dep+1;
d[k].siz=1;
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^fa) {
Dfs1(e[i].y,k);
d[k].siz+=d[e[i].y].siz;
if (d[d[k].son].siz<d[e[i].y].siz) d[k].son=e[i].y;
}
rd[k]=co;
}
void Dfs2(int k,int top){
d[k].top=top;
if (d[k].son) Dfs2(d[k].son,top);
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^d[k].fa&&e[i].y^d[k].son) Dfs2(e[i].y,e[i].y);
}
int Lca(int x,int y){
while (d[x].top^d[y].top)
d[d[x].top].dep>d[d[y].top].dep?x=d[d[x].top].fa:y=d[d[y].top].fa;
return d[x].dep>d[y].dep?y:x;
}
LL c[2][N+9];
void Bit_add(int t,int x,LL v){if (!x) return;for (;x<=n;x+=x&-x) c[t][x]+=v;}
LL Bit_query(int t,int x){LL sum=0;for (;x;x-=x&-x) sum+=c[t][x];return sum;}
LL Bit_query(int t,int l,int r){return Bit_query(t,r)-Bit_query(t,l-1);}
LL Query_chain(int x){return Bit_query(1,ld[x])*d[x].dep+Bit_query(0,ld[x]);}
LL Query_chain(int x,int y){
int lca=Lca(x,y);
return Query_chain(x)+Query_chain(y)-Query_chain(lca)-Query_chain(d[lca].fa);
}
void Add_node(int x,LL v){Bit_add(0,ld[x],v);Bit_add(0,rd[x]+1,-v);}
void Add_tree(int x,LL v){Bit_add(1,ld[x],v);Bit_add(1,rd[x]+1,-v);Add_node(x,-v*(d[x].dep-1));}
void Build(){for (int i=1;i<=n;++i) Add_node(i,(LL)v[i]);}
Abigail into(){
int x,y;
n=Ri();m=Ri();rot=Ri();
for (int i=1;i<=n;++i)
v[i]=Ri();
for (int i=1;i<n;++i){
x=Ri();y=Ri();
Ins(x,y);Ins(y,x);
}
}
Abigail work(){
Dfs1(rot,0);
Dfs2(rot,rot);
Build();
}
Abigail getans(){
int opt,a,x;
while (m--){
opt=Ri();a=Ri();x=Ri();
switch (opt){
case 1:
Add_node(a,(LL)x);
break;
case 2:
Add_tree(a,(LL)x);
break;
case 3:
printf("%lld\n",Query_chain(a,x));
break;
}
}
}
int main(){
into();
work();
getans();
return 0;
}