题解 CF1260F 【Colored Tree】
请到博客查看
首先设根为
再设
对于两个点
首先考虑
注意到,对于一个点
则
显然可以把
接下来考虑
设
注意到当我们加入一个点
树剖 + 树状数组即可。
总时间复杂度
const int N = 1e5 + 7;
int n, C, l[N], r[N], d[N], f[N], s[N], son[N], dfn[N], rnk[N], top[N], num;
modint g[N], vg[N], p, vp, now, A1, A2, A3, ans, c1[N], c2[N];
vi e[N], L[N], R[N];
void dfs(int x) {
s[x] = 1;
for (ui i = 0; i < e[x].size(); i++) {
int y = e[x][i];
if (y == f[x]) continue;
d[y] = d[x] + 1;
f[y] = x;
dfs(y);
s[x] += s[y];
if (s[y] > s[son[x]]) son[x] = y;
}
}
void dfs(int x, int p) {
top[x] = p;
dfn[x] = ++num;
rnk[num] = x;
if (!son[x]) return;
dfs(son[x], p);
for (ui i = 0; i < e[x].size(); i++) {
int y = e[x][i];
if (y == f[x] || y == son[x]) continue;
dfs(y, y);
}
}
inline void add(modint *c, int x, modint k) {
while (x <= n + 1) c[x] += k, x += x & -x;
}
inline modint ask(modint *c, int x) {
modint ret = 0;
while (x) ret += c[x], x -= x & -x;
return ret;
}
inline void Add(int x, modint k) {
while (x) {
add(c1, dfn[top[x]], k);
add(c1, dfn[x] + 1, -k);
add(c2, dfn[top[x]], k * dfn[top[x]]);
add(c2, dfn[x] + 1, -k * (dfn[x] + 1));
x = f[top[x]];
}
}
inline modint Ask(int x) {
modint ret = -(ask(c1, 1) * 2 - ask(c2, 1));
while (x) {
ret += ask(c1, dfn[x]) * (dfn[x] + 1) - ask(c2, dfn[x]);
ret -= ask(c1, dfn[top[x]] - 1) * dfn[top[x]] - ask(c2, dfn[top[x]] - 1);
x = f[top[x]];
}
return ret;
}
int main() {
rd(n), p = 1;
for (int i = 1; i <= n; i++) {
rd(l[i]), rd(r[i]);
g[i] = r[i] - l[i] + 1;
vg[i] = g[i] ^ -1;
p *= g[i];
C = max(C, r[i]);
L[l[i]].pb(i), R[r[i]].pb(i);
}
for (int i = 1, x, y; i < n; i++)
rd(x), rd(y), e[x].pb(y), e[y].pb(x);
vp = p ^ -1;
dfs(1);
dfs(1, 1);
for (int c = 1; c <= C; c++) {
for (ui i = 0; i < L[c].size(); i++) {
int x = L[c][i];
A1 += d[x] * vg[x];
A2 += vg[x];
A3 += d[x] * vg[x] * vg[x];
now += Ask(x) * vg[x];
Add(x, vg[x]);
}
ans += A1 * A2 - A3 - 2 * now;
for (ui i = 0; i < R[c].size(); i++) {
int x = R[c][i];
A1 -= d[x] * vg[x];
A2 -= vg[x];
A3 -= d[x] * vg[x] * vg[x];
Add(x, -vg[x]);
now -= Ask(x) * vg[x];
}
}
print(ans * p);
return 0;
}