题解 P5666 【树的重心【民间数据】】

Mr_Wu

2019-11-17 18:26:07

Solution

先将树变成以 $1$ 为根的有根树,并约定 $T(u)$ 为 $u$ 的子树,$T$ 为整棵树,$p(u,T)$ 表示 $u$ 是 $T$ 的重心 ---- 考虑一些简单的手法: $$ \begin{aligned} & \sum_{(fa_u,u)\in E} \big(\sum_{p(x,T(u))} x + \sum_{p(y,T-T(u))} \big) \\ & = \sum_x x\sum_{u\not= 1} [p(x,T(u))]+\sum_x x\sum_{u\not= 1} [p(x,T-T(u))] \end{aligned} $$ ---- 考虑研究若 $p(x,T(u))$,则 $x,u$ 满足什么性质。 设 $wson$ 为 $x$ 的 $siz$ 最大的儿子。 事实上 $p(x,T(u))$ 当且仅当: $$ \left\{ \begin{aligned} & x\in T(u) \\ & siz_{wson}\le \lfloor \frac{siz_u}{2}\rfloor \\ & siz_u-siz_x\le \lfloor \frac{siz_u}{2}\rfloor \end{aligned} \right. $$ 考虑到 $\forall x\in Z$,$x\le \lfloor a\rfloor \Leftrightarrow x\le a$,因此后两个式子直接化为 $$ 2siz_{wson}\le siz_u\le 2siz_x$$ ---- 考虑研究若 $p(x,T-T(u))$,则 $x,u$ 满足什么性质。 ### Situation 1 首先考虑 $u\in T(x)-\{x\}$,设 $v$ 为 $x$ 的儿子,且 $u\in T(v)$ (显然 $v$ 存在且唯一), ![](https://cdn.luogu.com.cn/upload/image_hosting/q4deau01.png) 设 $wson$ 为除去 $v$,$x$ 的 $siz$ 最大的儿子。(若没有,则认为 $siz_{wson}=0$) $$ \left\{ \begin{aligned} & siz_{wson}\le \lfloor \frac{n-siz_u}{2}\rfloor \\ & siz_v-siz_u\le \lfloor \frac{n-siz_u}{2}\rfloor \\ & n-siz_x\le \lfloor \frac{n-siz_u}{2}\rfloor \\ \end{aligned} \right. $$ 即 $$ 2siz_v-n\le siz_u\le \min\{n-2siz_{wson},2siz_x-n\} $$ ### Situation 2 然后考虑 $u\in T-T(x)-\{fa|p(x,T(fa))\}$ (即 $u$ 不在 $x$ 子树里也不是 $x$ 祖先),设 $wson$ 为 $x$ 的 $siz$ 最大的儿子。 $$ \left\{ \begin{aligned} & siz_{wson}\le \lfloor \frac{n-siz_u}{2}\rfloor \\ & n-siz_u-siz_x\le \lfloor \frac{n-siz_u}{2}\rfloor \\ \end{aligned} \right. $$ 也即 $$n-2siz_x \le siz_u \le n-2siz_{wson}$$ ---- 此时你已经有 40pts 了。 枚举 $x$,以计算 **Situation 1** 为例,你可以将这划分为两个这样的询问:问 $dfn_u\in [dfn_x,dfn_x+siz_x-1]$ 且 $siz_u\in [1,R](R \in [1,n])$ 的 $u$ 有多少个。 这已经十分显然了,将这 $2n$ 个询问直接离线,建一棵值域树状数组,并按照 $siz_x$ 升序依次加入,查询时直接查询区间和。 对于其它的给读者留作练习。 时间复杂度 $O(n\log n)$。 ---- ### 代码 ~~开 O2 才能过~~ ```cpp #include <cstdio> #include <algorithm> typedef long long ll; ll read() { ll ret = 0; char c = getchar(); while (c < '0' || c > '9') c = getchar(); while (c >= '0' && c <= '9') ret = ret * 10 + c - '0', c = getchar(); return ret; } inline int min(int a, int b) { return a < b ? a : b; } inline int max(int a, int b) { return a > b ? a : b; } inline int abs(int x) { return x > 0 ? x : -x; } const int MAXN = 700005; int T, N; ll ans; struct node { int v, next; } E[MAXN << 1]; int head[MAXN], Elen; void add(int u, int v) { ++Elen, E[Elen].v = v, E[Elen].next = head[u], head[u] = Elen; } int fa[MAXN], siz[MAXN], wson[MAXN], dfn[MAXN], dfncnt; void dfs(int u, int ff) { fa[u] = ff, siz[u] = 1, dfn[u] = ++dfncnt; int i; for (i = head[u]; i; i = E[i].next) { if (E[i].v == ff) continue; dfs(E[i].v, u), siz[u] += siz[E[i].v]; if (siz[E[i].v] > siz[wson[u]]) wson[u] = E[i].v; } } struct fenwick { int tree[MAXN]; inline int lowbit(int x) { return x & -x; } inline void insert(int pos, int k) { for (; pos <= N; pos += lowbit(pos)) tree[pos] += k; } inline int query(int pos) { int ret = 0; for ( ; pos; pos -= lowbit(pos)) ret += tree[pos]; return ret; } void clear() { for (int i = 1; i <= N; ++i) tree[i] = 0; } } T1, T2; struct query { int typ, val, x, k; query() {} query(int typ, int val, int x, int k) : typ(typ), val(val), x(x), k(k) {} } Q[MAXN << 4]; int Qlen; bool cmp(query q1, query q2) { return q1.k < q2.k; } int mxl[MAXN], mxr[MAXN]; void qaq(int pre, int id, int ff) { int sz = E[id].v == ff ? 0 : siz[E[id].v]; mxl[id] = max(mxl[pre], sz); if (E[id].next) qaq(id, E[id].next, ff); mxr[id] = max(mxr[E[id].next], sz); } struct data { int x, id; } D[MAXN]; bool cmpd(data d1, data d2) { return d1.x < d2.x; } int S[MAXN]; //int answer[MAXN]; int main() { #ifndef ONLINE_JUDGE freopen("test.in", "r", stdin), freopen("test.out", "w", stdout); #endif scanf("%d", &T); int i, j, prej, u, v; while (T--) { scanf("%d", &N); for (i = 1; i < N; ++i) scanf("%d%d", &u, &v), add(u, v), add(v, u); dfs(1, 0); for (i = 1; i <= N; ++i) { Q[++Qlen] = query(2, i, i, 2 * siz[i]), Q[++Qlen] = query(2, -i, i, 2 * siz[wson[i]] - 1); qaq(0, head[i], fa[i]); for (j = head[i], prej = 0; j; prej = j, j = E[j].next) { if (E[j].v == fa[i]) continue; int maxson = max(mxl[prej], mxr[E[j].next]), v = E[j].v; //printf("i = %d, v = %d, maxson = %d, l = %d, r = %d\n", i, v, maxson, mxl[prej], mxr[E[j].next]); if (min(N - 2 * maxson, 2 * siz[i] - N) >= 2 * siz[v] - N) { Q[++Qlen] = query(1, i, E[j].v, min(N - 2 * maxson, 2 * siz[i] - N)); Q[++Qlen] = query(1, -i, E[j].v, 2 * siz[v] - N - 1); } } Q[++Qlen] = query(3, i, N - 2 * siz[i], N - 2 * siz[wson[i]]); Q[++Qlen] = query(2, -i, fa[i], N - 2 * siz[wson[i]]), Q[++Qlen] = query(2, i, fa[i], N - 2 * siz[i] - 1); Q[++Qlen] = query(1, -i, i, N - 2 * siz[wson[i]]), Q[++Qlen] = query(1, i, i, N - 2 * siz[i] - 1); } //for (i = 1; i <= Qlen; ++i) printf("query(%d, %d, %d, %d)\n", Q[i].typ, Q[i].val, Q[i].x, Q[i].k); for (i = 2; i <= N; ++i) ++S[siz[i]]; for (i = 1; i <= N; ++i) S[i] += S[i - 1]; for (i = 1; i <= N; ++i) D[i].x = siz[i], D[i].id = i; std::sort(D + 1, D + N + 1, cmpd); std::sort(Q + 1, Q + Qlen + 1, cmp); j = 1; for (i = 1; i <= Qlen; ++i) { while (j <= N && D[j].x <= Q[i].k) { if (D[j].id != 1) T1.insert(dfn[D[j].id], 1), T2.insert(dfn[D[j].id], 1), T2.insert(dfn[D[j].id] + siz[D[j].id], -1); ++j; } //printf("query(%d, %d, %d, %d)\n", Q[i].typ, Q[i].val, Q[i].x, Q[i].k); int qaq; if (Q[i].typ == 3) { if (Q[i].x < 1) Q[i].x = 1; if (Q[i].k < 0) Q[i].k = 0; qaq = S[Q[i].k] - S[Q[i].x - 1]; } else if (Q[i].typ == 2) qaq = T2.query(dfn[Q[i].x]); else qaq = T1.query(dfn[Q[i].x] + siz[Q[i].x] - 1) - T1.query(dfn[Q[i].x] - 1); //printf("qaq = %d\n", qaq); ans += (ll)Q[i].val * qaq; //answer[abs(Q[i].val)] += Q[i].val * qaq; } //for (i = 1; i <= N; ++i) printf("answer[%d] = %d\n", i, answer[i] / i); printf("%lld\n", ans); T1.clear(), T2.clear(); for (i = 1; i <= N; ++i) head[i] = S[i] = wson[i] = dfn[i] = mxl[i] = mxr[i] = 0; Elen = dfncnt = Qlen = 0; ans = 0; } return 0; } ```