前言
刚学了长剖,比赛快结束的时候进来看了一眼,口胡秒了,写的时候发现巨大多细节,口胡不行。
长剖永存,空间卡的好啊!
题意
不做赘述。
思路
首先看到这是一道和深度有极大的关系,自然联想到建几个以深度为下标的数组通过 DFS 遍历并动态修改解决问题,而且可以用启发式合并的类似思路合并子树信息,因此能联想到用长链剖分解决问题。
但是长链剖分对数组空间和对子树信息继承关系要求比较苛刻,比如一开始我是这么想的:
- 记录 (val[u][i]) 表示以 (u) 为根的子树所有深度为 (i) 的节点到 (u) 的路径长度之和。
- 记录 (dis[u][i]) 表示以 (u) 为根的子树所有深度为 (i) 的节点之间的距离之和。
- 记录 (siz[u][i]) 表示以 (u) 为根的子树所有深度为 (i) 的节点的个数。
(dis[u]) 和 (siz[u]) 的转移都很好写:
[dis[u][i]=sum_{vin son(u)}dis[v][i-1]+(siz[u][i]-siz[v][i-1])*(val[v][i-1]+siz[v][i-1]*w(u,v))
]
(上面的公式在代码中为了方便并不是如此一模一样实现)
[siz[u][i]=[i==0]+sum_{vin son(n)}siz[v][i-1]
]
但是对于 (val[u]) 的转移就出了问题,因为 (val[u]) 的值和 (u) 这个点有关,也就是说从重儿子转移过来的还要加上一个值(还和 (siz[maxson(u)][i]) 有关),不能直接继承,而暴力再枚举一遍重儿子的深度再加显然复杂度错误。
以下与出题人思路不同。
但是还是可以优化的,我们可以再建一个 (tag[u]) 数组,即懒标记优化,每次 (u) 节点合并前,因为先继承了重儿子的 (val[u]) 数组,我们需要在 (tag[u][1]) 加上一个 (w(u,maxson(u))),当要访问 (val[u][i]) 的时候,我们要先访问懒标记,更新并下传,因为下穿懒标记在更新 (val[u][i]) 和 (siz[u][i]) 前,所以不会访问到 (dis[u][i]),所以加值延迟不会影响最终大小。
代码
感觉这样口胡还是有点难懂QwQ。
目前除出题人外的最优解,(rk1是数据改之前交的)。
int a, b, mx[N + 5],
son[N + 5][2];
LL op[N * 8 + 5], *tag[N + 5], ans[N + 5], *dis[N + 5], *val[N + 5], *tmp = op, *siz[N + 5];
vector<pii> st[N + 5], ask[N + 5];
void ins(int n, int len) {
val[n] = tmp;
tmp += len + 1;
dis[n] = tmp;
tmp += len + 1;
siz[n] = tmp;
tmp += len + 1;
tag[n] = tmp;
tmp += len + 1;
}
void add(int n, int i) {
(tag[n][i + 1] += tag[n][i]) %= mod;
(val[n][i] += tag[n][i] * siz[n][i] % mod) %= mod;
tag[n][i] = 0;
}
void dfs(int n, int fa) {
mx[n] = 1;
rep(i, 0, siz(st[n]) - 1) {
int v = st[n][i].fi;
if (v == fa) continue;
dfs(v, n);
if (mx[v] > mx[son[n][0]]) son[n][0] = v, son[n][1] = st[n][i].se;
}
mx[n] = mx[son[n][0]] + 1;
}
void Dfs(int n, int fa) {
if (son[n][0]) {
val[son[n][0]] = val[n] + 1;
dis[son[n][0]] = dis[n] + 1;
siz[son[n][0]] = siz[n] + 1;
tag[son[n][0]] = tag[n] + 1;
Dfs(son[n][0], n);
}
siz[n][0] = 1;
tag[n][1] = son[n][1];
rep(i, 0, siz(st[n]) - 1) {
int v = st[n][i].fi, p = st[n][i].se;
if (v == fa || v == son[n][0]) continue;
ins(v, mx[v]);
Dfs(v, n);
rep(j, 1, mx[v]) {
if (j != mx[v]) add(v, j);
add(n, j);
(dis[n][j] += val[n][j] * siz[v][j - 1] % mod +
(val[v][j - 1] + p * siz[v][j - 1] % mod) *
siz[n][j] % mod + dis[v][j - 1]) %= mod;
(val[n][j] += val[v][j - 1] + p * siz[v][j - 1] % mod) %= mod;
(siz[n][j] += siz[v][j - 1]) %= mod;
}
}
rep(i, 0, siz(ask[n]) - 1) {
int x = ask[n][i].fi;
ans[ask[n][i].se] = dis[n][x];
}
}
signed main() {
// freopen("in1.in", "r", stdin);
// freopen("out.out", "w", stdout);
a = read();
b = read();
int x, y, z;
rep(i, 1, a - 1) {
x = read();
y = read();
z = read();
st[x].PB(MP(y, z));
st[y].PB(MP(x, z));
}
dfs(1, 0);
rep(i, 1, b) {
x = read();
y = read();
if (y <= mx[x] - 1)
ask[x].PB(MP(y, i));
}
ins(1, mx[1]);
Dfs(1, 0);
rep(i, 1, b) printf("%lld
", ans[i]);
return 0;
}