【題解】CF526G-Spiders Evil Plan
阿新 • • 發佈:2022-05-07
難度很高的樹上綜合題。
首先我們考慮沒有 \(x\) 限制,\(q=1\) 的情況。也就是我們要選出若干條路徑使得並集的邊權和最大。
我們選擇的路徑一定形成一個連通塊,否則存在存在兩條路徑 \((x,y)\) 和 \((a,b)\) 不相交,我們可以調整為 \((x,b)\) 和 \((a,y)\)。
如果我們固定路徑一端,那麼另一端一定距離最遠,一定是樹的直徑兩端中的一個。所以我們以直徑端點為根,那麼等價於選擇 \(2y-1\) 條到根的路徑使得並集最大。
一個簡易的貪心是每次選擇最長的鏈,然後將鏈刪掉。這個貪心是正確的,我們可以用費用流模型解釋,因為樹形結構的存在,費用流不存在退流的情況,所以貪心是正確的。
同時觀察一下,每次選擇最長的鏈,這本質上就是長鏈剖分的過程,剖分後按鏈長排序後依次選擇即可。
那麼接下來考慮 \(x\) 的限制。如果 \(x\) 在前 \(2y-1\) 條鏈裡面,那麼可以直接得到答案。
如果不在裡面,我們仍然用調整法將答案調整至最優。我們先找到 \(x\) 最近的在前 \(2y-2\) 條鏈裡面的祖先 \(y\),選擇將第 \(2y-1\) 條鏈替換成 \((x,y)\),或者找到在前 \(2y-1\) 條鏈裡面的祖先 \(z\),將 \(z\) 下面接的單鏈替換成經過 \(x\) 的最長鏈。
距離可以倍增實現,時間複雜度 \(\mathcal{O}(N\log N)\)
#define N 100005 int n, q, t, d[N]; vector<Pr>e[N]; void dfs(int x,int fa){ go(y, e[x])if(y.fi != fa)d[y.fi] = d[x] + y.se, dfs(y.fi, x); } struct node{ int f[N][17], d[N], ds[N], son[N], dfn[N], idx, rt, mat[N], s[N]; Pr w[N]; void dfs(int x,int fa){ d[x] = 0; go(y, e[x])if(y.fi != fa){ ds[y.fi] = ds[x] + y.se, dfs(y.fi, x); if(d[y.fi] + y.se >= d[x])son[x] = y.fi, d[x] = d[y.fi] + y.se; } } void dfs2(int x,int fa,int id){ f[x][0] = fa, dfn[x] = id; rp(i, t)f[x][i] = f[f[x][i - 1]][i - 1]; if(!son[x])return; dfs2(son[x], x, id); go(y, e[x])if(y.fi != fa && y.fi != son[x]) w[++idx].fi = d[y.fi] + y.se, dfs2(y.fi, x, idx); } void init(int x){ dfs(rt = x, 0); w[++idx].fi = d[rt], dfs2(rt, 0, idx); rp(i, idx)w[i].se = i; sort(w + 1, w + idx + 1, [](Pr x, Pr y){return x > y;}); rp(i, idx)mat[w[i].se] = i, s[i] = s[i - 1] + w[i].fi; } int ask(int x,int y){ y = y + y - 1; if(mat[dfn[x]] <= y)return s[min(y, idx)]; int v = x; pre(i, t, 0)if(mat[dfn[f[v][i]]] > y)v = f[v][i]; v = f[v][0]; int ans = s[y] - d[v] + ds[x] - ds[v] + d[x]; v = x; pre(i, t, 0)if(mat[dfn[f[v][i]]] >= y)v = f[v][i]; v = f[v][0]; cmx(ans, s[y - 1] + d[x] + ds[x] - ds[v]); return ans; } }A, B; int main() { read(n, q), t = log2(n); rp(i, n - 1){ int x, y, z; read(x, y, z); e[x].pb(mp(y, z)), e[y].pb(mp(x, z)); } dfs(1, 0); int X = 1, Y = 1; rp(i, n)if(d[i] > d[X])X = i; d[X] = 0, dfs(X, 0); rp(i, n)if(d[i] > d[Y])Y = i; A.init(X), B.init(Y); int lst = 0; while(q--){ int x, y; read(x, y); x = (x + lst - 1) % n + 1; y = (y + lst - 1) % n + 1; printf("%d\n", lst = max(A.ask(x, y), B.ask(x, y))); } return 0; }