1. 程式人生 > 其它 >【題解】CF526G-Spiders Evil Plan

【題解】CF526G-Spiders Evil Plan

難度很高的樹上綜合題。

首先我們考慮沒有 \(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;
}