Solution -「BZOJ 3331」壓力
阿新 • • 發佈:2020-07-22
\(\mathcal{Description}\)
Link.
給定一個 \(n\) 個點 \(m\) 條邊的連通無向圖,並給出 \(q\) 個點對 \((u,v)\),令 \(u\) 到 \(v\) 的路徑所必經的結點權值 \(+1\)。求最終每個結點的權值。
\(n\le10^5\),\(m,q\le2\times10^5\)。
\(\mathcal{Solution}\)
看到”必經之點“,應該考慮圓方樹。
對於每個點對,直接在圓方樹上作差分。具體地,兩個圓點的 tag++
,其 LCA 和 LCA 的父親(如果存在)的 tag--
,最後一遍 DFS 求每個圓點的子樹 tag
\(\mathcal{Code}\)
#include <cstdio> const int MAXN = 1e5, MAXM = 2e5; int n, m, q, snode; int dfc, top, dfn[MAXN + 5], low[MAXN + 5], stk[MAXN + 5]; int dep[MAXN * 2 + 5], fa[MAXN * 2 + 5][20], tag[MAXN * 2 + 5], sum[MAXN * 2 + 5]; struct Graph { int ecnt, head[MAXN * 2 + 5], to[MAXM * 2 + 5], nxt[MAXM * 2 + 5]; inline void link ( const int s, const int t ) { to[++ ecnt] = t, nxt[ecnt] = head[s]; head[s] = ecnt; } inline void add ( const int u, const int v ) { link ( u, v ), link ( v, u ); } } src, tre; inline bool chkmin ( int& a, const int b ) { return b < a ? a = b, true : false; } inline void Tarjan ( const int u, const int f ) { dfn[u] = low[u] = ++ dfc, stk[++ top] = u; for ( int i = src.head[u], v; i; i = src.nxt[i] ) { if ( ( v = src.to[i] ) == f ) continue; if ( ! dfn[v] ) { Tarjan ( v, u ), chkmin ( low[u], low[v] ); if ( low[v] >= dfn[u] ) { tre.add ( u, ++ snode ); do tre.add ( snode, stk[top] ); while ( stk[top --] ^ v ); } } else chkmin ( low[u], dfn[v] ); } } inline void init ( const int u, const int f ) { dep[u] = dep[fa[u][0] = f] + 1; for ( int i = 1; i <= 17; ++ i ) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for ( int i = tre.head[u], v; i; i = tre.nxt[i] ) { if ( ( v = tre.to[i] ) ^ f ) { init ( v, u ); } } } inline int calcLCA ( int u, int v ) { if ( dep[u] < dep[v] ) u ^= v ^= u ^= v; for ( int i = 17; ~ i; -- i ) if ( dep[fa[u][i]] >= dep[v] ) u = fa[u][i]; if ( u == v ) return u; for ( int i = 17; ~ i; -- i ) if ( fa[u][i] ^ fa[v][i] ) u = fa[u][i], v = fa[v][i]; return fa[u][0]; } inline void calcAns ( const int u, const int f ) { sum[u] = tag[u]; for ( int i = tre.head[u], v; i; i = tre.nxt[i] ) { if ( ( v = tre.to[i] ) ^ f ) { calcAns ( v, u ), sum[u] += sum[v]; } } } int main () { scanf ( "%d %d %d", &n, &m, &q ), snode = n; for ( int i = 1, u, v; i <= m; ++ i ) { scanf ( "%d %d", &u, &v ); src.add ( u, v ); } Tarjan ( 1, 0 ), init ( 1, 0 ); for ( int i = 1, u, v; i <= q; ++ i ) { scanf ( "%d %d", &u, &v ); ++ tag[u], ++ tag[v]; int w = calcLCA ( u, v ); -- tag[w]; if ( fa[w] ) -- tag[fa[w][0]]; } calcAns ( 1, 0 ); for ( int i = 1; i <= n; ++ i ) printf ( "%d\n", sum[i] ); return 0; }