Solution -「LOCAL」畫畫圖
阿新 • • 發佈:2020-08-13
\(\mathcal{Description}\)
給定一棵 \(n\) 個點的樹形隨機的帶邊權樹,求所有含奇數條邊的路徑中位數之和。樹形生成方式為隨機取不連通兩點連邊直到全部連通。
\(n\le32000\)。
\(\mathcal{Solution}\)
考慮用中位數的標準姿勢統計每條邊的貢獻——小於它的設為 \(-1\),大於它的設為 \(+1\),邊權相等按編欽定大小關係。那麼這條邊的貢獻就是路徑兩端權值加和為 \(0\) 的路徑對數(顯然每對路徑連起來都是奇數路徑)。
令 \(f(u,i)\) 表示 \(u\) 子樹內到 \(u\) 路徑權值和為 \(i\)
複雜度 \(\mathcal O(n^2)\),不過可以算出帶一個 \(\frac{1}6\) 的常數,所以可過。
\(\mathcal{Code}\)
#include <queue> #include <cstdio> #include <cstring> typedef long long LL; const int MAXN = 32000, MAXSQRT = 180, MAXV = 1e6; int n, ecnt, head[MAXN + 5], fa[MAXN + 5], dep[MAXN + 5], faw[MAXN + 5]; int mempool[MAXN * MAXSQRT * 2], *f[MAXN + 5], *frepos = mempool, *g; int pre[MAXN + 5], buc[MAXV + 5], ori[MAXN + 5], down[MAXN + 5]; struct Edge { int to, cst, nxt; } graph[MAXN * 2 + 5]; struct EdgeSet { int u, v, w; } eset[MAXN + 5]; inline int rint () { int x = 0; char s = getchar (); for ( ; s < '0' || '9' < s; s = getchar () ); for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' ); return x; } inline int min_ ( const int a, const int b ) { return a < b ? a : b; } inline int max_ ( const int a, const int b ) { return a < b ? b : a; } inline void link ( const int s, const int t, const int c ) { graph[++ ecnt] = { t, c, head[s] }; head[s] = ecnt; } inline void BFS ( const int s ) { static std::queue<int> que; que.push ( s ); dep[s] = 1; while ( ! que.empty () ) { int u = que.front (); que.pop (); for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( ! dep[v = graph[i].to] ) { pre[v] = u, dep[v] = dep[u] + 1; que.push ( v ); } } } } inline void init ( const int u ) { dep[u] = 0; for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( ( v = graph[i].to ) ^ fa[u] ) { fa[v] = u, faw[v] = 1, down[graph[i].cst] = v, init ( v ); if ( dep[v] + 1 > dep[u] ) dep[u] = dep[v] + 1; } } f[u] = frepos += dep[u] + 1, frepos += dep[u] + 1; } inline void DP ( const int u ) { *f[u] = 1; for ( int i = head[u], v; i; i = graph[i].nxt ) { if ( ( v = graph[i].to ) ^ fa[u] ) { DP ( v ); for ( int j = -dep[v]; j <= dep[v]; ++ j ) f[u][j + 1] += f[v][j]; } } } inline LL update ( const int s ) { int l = -dep[s], r = dep[s]; faw[s] = -1; for ( int u = fa[s], v = s, d1 = 0, d2 = 0; u; u = fa[v = u] ) { d1 += v ^ s ? faw[v] : 1, d2 += faw[v]; for ( int i = -dep[s]; i <= dep[s]; ++ i ) { f[u][i + d1] -= f[s][i]; f[u][i + d2] += f[s][i]; } for ( int i = max_ ( -dep[u], l ), t = min_ ( dep[u], r ), d = d2 + 1; i <= t; ++ i ) { g[i + d] += f[u][i] - f[v][i - faw[v]]; } l -= faw[u], r -= faw[u]; } LL ret = 0; for ( int i = -dep[s]; i <= dep[s]; ++ i ) { ret += 1ll * f[s][i] * g[-i]; g[-i] = 0; } return ret; } int main () { n = rint (); int mxw = 0; for ( int i = 1, u, v, w; i < n; ++ i ) { u = rint (), v = rint (), w = rint (); eset[i] = { u, v, w }, ++ buc[w]; if ( w > mxw ) mxw = w; } for ( int i = 2; i <= mxw; ++ i ) buc[i] += buc[i - 1]; for ( int i = 1; i < n; ++ i ) { eset[i].w = buc[ori[buc[eset[i].w]] = eset[i].w] --; link ( eset[i].u, eset[i].v, eset[i].w ); link ( eset[i].v, eset[i].u, eset[i].w ); } BFS ( 1 ); int s = 0, t = 0; for ( int i = 1; i <= n; ++ i ) { if ( dep[i] > dep[s] ) s = i; dep[i] = pre[i] = 0; } BFS ( s ); for ( int i = 1; i <= n; ++ i ) if ( dep[i] > dep[t] ) t = i; for ( int i = dep[s] + dep[t] - 2 >> 1; i --; t = pre[t] ); init ( t ), DP ( t ); g = frepos += dep[t] + 1, frepos += dep[t] + 1; LL ans = 0; for ( int i = 1; i < n; ++ i ) ans += ori[i] * update ( down[i] ); printf ( "%lld\n", ans ); return 0; }