回忆
Register_int · · 题解
O(n^2)
你发现
O(n \log^2 n)
离线把树建出来。可以发现每加一个点相当于给一条链
- 向上找到要
+1 的链的端点。 - 把答案加上这条链上
a_i 的和。 - 给链
+1 。
可以树剖套线段树二分简单做掉。直接维护
O(n\log n)
毛毛虫坐火箭包。给 LCT、全局平衡二叉树、以及被卡常的正解。期望得分
O(n)
树剖菜了,究其本质就是重链剖分跟这个
考虑长剖,从叶子往根做,转而维护每个点加入时答案的变化量。对于每个点
现在我们要处理
对于长儿子的继承,直接继承其加法标记,加上自己的
关于复杂度分析,标记的插入删除可以链表维护,由于长链维护的有效标记的数量不会大于长链长度,可以沿用长剖的复杂度分析,总复杂度
#include <bits/stdc++.h>
using namespace std;
// fastIO by d0j1a_1701
typedef long long ll;
const int MAXN = 5e6 + 10;
const int mod = 1e9 + 7;
inline int add(int x, int y) { return x += y, x < mod ? x : x - mod; }
inline int sub(int x, int y) { return x -= y, x < 0 ? x + mod : x; }
inline void cadd(int &x, int y) { x += y, x < mod || (x -= mod); }
inline void csub(int &x, int y) { x -= y, x < 0 && (x += mod); }
vector<int> g[MAXN]; int d[MAXN], md[MAXN], son[MAXN];
void init(int u) {
for (int v : g[u]) {
md[v] = d[v] = d[u] + 1, init(v);
md[u] = max(md[u], md[v]);
if (md[son[u]] < md[v]) son[u] = v;
}
}
int n, a[MAXN], ans[MAXN], tag[MAXN];
struct node {
int x, nxt;
node() : x(0), nxt(0) {}
} l[MAXN];
void dfs(int u) {
if (!son[u]) return ;
dfs(son[u]), tag[u] = tag[son[u]], l[u].nxt = son[u];
for (int v : g[u]) {
if (v == son[u]) continue; dfs(v); int lst = u;
for (int i = l[u].nxt, j = v; j; i = l[i].nxt, j = l[j].nxt) {
if (i < j) ans[j] = add(l[j].x, tag[v]), lst = i;
else {
ans[i] = add(l[i].x, tag[u]);
l[lst].nxt = j, swap(l[i].nxt, l[j].nxt);
swap(i, j), lst = i;
cadd(l[i].x, sub(tag[v], tag[u]));
}
}
}
cadd(tag[u], a[u]); if (tag[u]) l[u].x = mod - tag[u];
}
int main() {
io.read(n, a[1]), n++;
for (int i = 2, u; i <= n; i++) io.read(u, a[i]), g[u].emplace_back(i);
init(1), dfs(1);
for (int i = l[1].nxt; i; i = l[i].nxt) ans[i] = add(l[i].x, tag[1]);
for (int i = 2; i <= n; i++) cadd(ans[i], ans[i - 1]), io.writeln(ans[i]);
}
这个放 T2 对洛谷来说可能还是有点超前了。