题目:LOJ146.
题目大意:给定一棵 n n n个点的树,要求支持以下操作:
1.格式 1   a   b   c 1\,a\,b\,c 1abc,表示把链 ( a , b ) (a,b) (a,b)上的点点权加上 c c c.
2.格式 2   a 2\,a 2a,表示查询点 a a a的点权.
3.格式 3   a 3\,a 3a,表示查询点 a a a的子树点权和.
设操作次数为 m m m,则 1 ≤ n , m ≤ 1 0 6 1\leq n,m\leq 10^6 1≤n,m≤106.
本来的想法是给大力跑出这棵树的dfs序,然后用 1 1 1和 − 1 -1 −1标号,并用线段树维护的,但是线段树常数太大貌似并过不了这道题…
于是我们考虑换用树状数组,仍然利用dfs序,只不过现在我们变成了用dfs序维护每个点到根这些链被直接会被增加多少,也可以看做是自底向上的差分,我们记点 k k k的这个值为 v [ k ] v[k] v[k].
然后我们维护链加就变成了直接给一个点加,当然由于不是一个点到根的链需要用到树上差分;查询点权变成了查询子树和;查询子树和…等等子树和怎么搞?
容易发现查询 x x x的子树和,可以统计子树中每个节点 k k k的贡献,容易发现节点 k k k的贡献为 v [ k ] ∗ ( d e p [ k ] − d e p [ x ] + 1 ) v[k]*(dep[k]-dep[x]+1) v[k]∗(dep[k]−dep[x]+1),其中 d e p [ k ] dep[k] dep[k]表示 k k k的深度.那么我们发现这个式子可以拆成 v [ k ] ∗ d e p [ k ] − v [ k ] ∗ ( d e p [ x ] − 1 ) v[k]*dep[k]-v[k]*(dep[x]-1) v[k]∗dep[k]−v[k]∗(dep[x]−1),后半个我们已经维护了 v [ k ] v[k] v[k]之和再乘 d e p [ x ] − 1 dep[x]-1 dep[x]−1即可,前半个我们可以通过多用一个树状数组维护 v [ k ] ∗ d e p [ k ] v[k]*dep[k] v[k]∗dep[k]来实现.
时间复杂度 O ( ( n + m ) log n ) O((n+m)\log n) O((n+m)logn).注意这道题卡常严重,建议输入用快读且找LCA用树剖或者tarjan.
代码如下:
#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;
}
struct side{
int y,next;
}e[N*2+9];
int lin[N+9],top,n,m,rot;
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,siz,dep;
}d[N+9];
LL c[2][N+9],v[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?x:y;
}
void Bit_add(int t,int x,LL v){if (x==0) 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);}
void Add_chain(int x,int y,LL v){
int lca=Lca(x,y);
Bit_add(0,ld[x],v);Bit_add(0,ld[y],v);
Bit_add(0,ld[lca],-v);Bit_add(0,ld[d[lca].fa],-v);
Bit_add(1,ld[x],v*d[x].dep);Bit_add(1,ld[y],v*d[y].dep);
Bit_add(1,ld[lca],-v*d[lca].dep);Bit_add(1,ld[d[lca].fa],-v*d[d[lca].fa].dep);
}
void Build(){for (int i=1;i<=n;++i) Add_chain(i,i,v[i]);}
LL Query_node(int x){return Bit_query(0,ld[x],rd[x]);}
LL Query_tree(int x){return Bit_query(1,ld[x],rd[x])-Bit_query(0,ld[x],rd[x])*(d[x].dep-1);}
Abigail into(){
n=Ri();m=Ri();rot=Ri();
int x,y;
for (int i=1;i<=n;++i) v[i]=(LL)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,x,y,c;
while (m--){
opt=Ri();
switch (opt){
case 1:
x=Ri();y=Ri();c=Ri();
Add_chain(x,y,(LL)c);
break;
case 2:
x=Ri();
printf("%lld\n",Query_node(x));
break;
case 3:
x=Ri();
printf("%lld\n",Query_tree(x));
break;
}
}
}
int main(){
into();
work();
getans();
return 0;
}