Loading

【题解】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;
}
posted @ 2022-05-07 12:34  7KByte  阅读(35)  评论(0编辑  收藏  举报