bzoj 5477 星际穿越

$dfs$ 序 + 树状数组.

  • 由于路径的权是点权,可以考虑每个点被多少条路径经过,乘上它的点权即为贡献.
  • 假设当前询问是在子树 $p$ 内,考虑一个点 $i$ ,在子树 $i$ 内与不在子树 $i$ 内的点形成了 $siz[i]\cdot (siz[p]-siz[i]+1)$ 条路径,都经过了点 $i$ .
  • 还有一部分路径是将 $i$ 作为 $LCA$ 经过.显然每两个在 $i$ 的不同儿子形成的子树内的点都会经过 $i$ .这部分路径数目可以在 $dfs$ 时利用前缀和算出,记作 $k[i]$ .
  • 由于修改只会单点修改点权,不改变树的形态,把那个 $siz[p]$ 拆出去算,预处理出每个点的剩下的系数.
  • 直接利用 $dfs$ 序,树状数组维护答案.
  • 记 $w[i]=k[i]+siz[i]\cdot (1-siz[u])​$ .
  • 那么每次询问的答案就是子树 $p​$ 内的 $siz[p]\cdot (\sum siz[i]\cdot val[i])+(\sum w[i]\cdot val[i])​$ .
  • 开两个树状数组分别维护前缀 $\sum siz\cdot val$ 与 $\sum siz\cdot w$ 就好了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
fh=-1,jp=getchar();
while (jp>='0'&&jp<='9')
out=out*10+jp-'0',jp=getchar();
return out*fh;
}
const int MAXN=2e5+10;
const int P=1e9+7;
int n,m;
inline int add(int a,int b)
{
return (a + b) % P;
}
inline int mul(int a,int b)
{
return 1LL * a * b % P;
}
struct FenwickTree
{
#define lowbit(x) x&(-x)
int bit[MAXN];
FenwickTree(){memset(bit,0,sizeof bit);}
void upd(int x,int c)
{
for(;x<=n;x+=lowbit(x))
bit[x]=add(bit[x],c);
}
int sum(int x)
{
int s=0;
for(;x;x-=lowbit(x))
s=add(s,bit[x]);
return s;
}
int query(int l,int r)
{
return add(sum(r),P-sum(l-1));
}
};
int ecnt=0,head[MAXN],to[MAXN<<1],nx[MAXN<<1],val[MAXN];
void addedge(int u,int v)
{
++ecnt;
to[ecnt]=v;
nx[ecnt]=head[u];
head[u]=ecnt;
}
int siz[MAXN],dfn[MAXN],idx=0;
int k[MAXN],w[MAXN];
void dfs(int u,int fa)
{
dfn[u]=++idx;
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v==fa)
continue;
dfs(v,u);
k[u]=add(k[u],mul(siz[v],siz[u]));
siz[u]+=siz[v];
}
siz[u]++;
}
FenwickTree T1;//siz*val
FenwickTree T2;//w*val
void init()
{
for(int i=1;i<=n;++i)
{
T1.upd(dfn[i],mul(siz[i],val[i]));
w[i]=add(k[i],mul(siz[i],P+1-siz[i]));
T2.upd(dfn[i],mul(w[i],val[i]));
}
}
int main()
{
n=read(),m=read();
for(int i=1;i<n;++i)
{
val[i]=1;
int u=read(),v=read();
addedge(u,v);
addedge(v,u);
}
val[n]=1;
dfs(1,0);
init();
while(m--)
{
int op=read();
if(op==1)
{
int p=read(),x=read();
T1.upd(dfn[p],mul(siz[p],x));
T2.upd(dfn[p],mul(w[p],x));
}
else
{
int p=read();
int ans=T2.query(dfn[p],dfn[p]+siz[p]-1);
ans=add(ans,mul(siz[p],T1.query(dfn[p],dfn[p]+siz[p]-1)));
printf("%d\n",ans);
}
}
return 0;
}