2020-11-23

注:作者YWhgs大佬,我只是不知道怎么把文件发到团队里,我自己写完题解会替换掉
对于 20 20 20% 的数据, n ≤ 1000 n \leq 1000 n≤1000。

显然对于这一档部分分我们可以枚举每一个点 x x x,比较一下 1 1 1 和 x x x 哪个先到 i i i,然后取个 min ⁡ \min min 就好了。复杂度 O ( n 2 ) O(n^2) O(n2)。其实还可以剪个枝,数据水,可以拿到 80 分。

对于树的数据。

考虑到一棵树 每一条树上路径的边 都是固定的,所以可以直接找 1 → x 1 \to x 1→x 的中点,如果长度为奇数,找 1 → x 1 \to x 1→x 距离 x x x 为 ⌊ d i s t a n c e ( 1 , x ) 2 ⌋ \lfloor \frac{distance(1,x)}{2} \rfloor ⌊2distance(1,x)​⌋ 的那个点 y y y,答案就是 s z y sz_y szy​。但是经过一番仔细思考,你会发现可以直接枚举 1 1 1 的儿子作为 y y y 就可以了,非常简单,这个直接取 n − m a x ( s z y ) n - max(sz_y) n−max(szy​)。复杂度 O ( n ) O(n) O(n)。

对于 100 100 100% 的数据, n ≤ 1 0 5 n \leq 10^5 n≤105。

定义 K ( x , k ) K(x,k) K(x,k) 为 x x x 的 k k k 级祖先。

发现可以先搞出一颗 bfs 弄出来的一颗树,然后多出来的边不会超过 100 100 100 条,即多出来的点不会超过 200 200 200 个。把这 200 200 200 个点定义为 特殊点。然后非常容易想到,对这 200 200 200 个特殊点遍历整个图,求出这些点到其他点的最短距离。

然后就是在这棵树上做文章了。发现一个 特殊点 对一个点 x x x 有用,当且仅当这个点 y y y 离 x x x 的距离 d i s t a n c e x , y distance_{x,y} distancex,y​小于等于 d i s t a n c e 1 , y distance_{1,y} distance1,y​,然后对于这个点它能更新到的部分其实是 K ( y , ⌊ d i s t a n c e ( 1 , y ) − d i s t a n c e ( x , y ) 2 ⌋ ) K(y,\lfloor \frac{distance(1,y)-distance(x,y)}{2} \rfloor) K(y,⌊2distance(1,y)−distance(x,y)​⌋) 的所有儿子。

然后对于所有的特殊点,其实是有重叠部分的,如果有重叠部分的话,那么 L y ≤ d f n y ′ ≤ R y L_y \leq dfn_y' \leq R_y Ly​≤dfny′​≤Ry​。这个是一个经典的判 y ′ y' y′ 是否在 y y y 子树内的方法,其中 L , R L,R L,R 指的是这一个子树区间。当然你可以理解成 R i = L i + s i z e i − 1 R_i = L_i + size_i - 1 Ri​=Li​+sizei​−1。然后就可以去排个序,扫描一下,就可以搞完了。

下面这份代码有点离谱,原意是离线下来然后去掉一个 log ⁡ \log log 的倍增和排序的复杂度…谁知道越跑越慢。。。可能是实现比较烂。。

感觉写个长链剖分比直接离线 d f s dfs dfs 一遍求 K ( x ) K(x) K(x) 要快啊。。

warning:下面这份代码空间需求大概比较大,建议长链剖分 O(1) 求 K(x)。

复杂度 O ( n ∗ 200 ) O(n * 200) O(n∗200)。

#include <bits/stdc++.h>
void cmin(int &x, const int &y) { x = (x < y) ? x : y; }
const int N = 262144;
int n, m;
std::vector<int> g[N];
int dis[N], order[N], cnt, sz[N], par[N];
int q[N], h, t;
int special[202], nodes;
void bfs1() {
	q[h = t = 1] = 1; dis[1] = 1;
	while (h <= t) {
		int u = q[h++]; order[++cnt] = u;
		for (auto v : g[u]) {
			if (!dis[v]) {
				dis[v] = dis[u] + 1;
				par[q[++t] = v] = u;
			}
		}
	}
}
int dist[202][N];
void bfs(int i, int s) {
	q[h = t = 1] = s; dist[i][s] = 1;
	while (h <= t) {
		int u = q[h++];
		for (auto v : g[u]) {
			if (!dist[i][v]) {
				dist[i][q[++t] = v] = dist[i][u] + 1;
			}
		}
	}
}
int L[N], R[N], Index;
void dfs(int u) {
	L[u] = ++Index;
	for (auto v : g[u]) {
		if (par[v] == u) {
			dfs(v);
		}
	}
	R[u] = Index;
}
std::vector<std::pair<int, int> > task[N];
std::vector<int> hav[N];
void calc(int u, int k, int id) {
	if (dis[u] < k) {
		return;
	} else {
		task[u].emplace_back(dis[u] - k >> 1, id);
	}
}
int stk[N], top;
void dfs2(int u) {
	stk[++top] = u;
	for (auto x : task[u]) {
		int k = x.first;
		hav[stk[top - k]].emplace_back(x.second);
	}
	for (auto v : g[u]) {
		if (par[v] == u) {
			dfs2(v);
		}
	}
	--top;
}
std::vector<int> v[N];
void dfs3(int u) {
	for (auto id : hav[u]) {
		v[id].emplace_back(u);
	}
	for (auto v : g[u]) {
		if (par[v] == u) {
			dfs3(v);
		}
	}
}
int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	freopen("starwar.in", "r", stdin);
	freopen("starwar.out", "w", stdout);	
	std::cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int x, y;
		std::cin >> x >> y;
		g[x].emplace_back(y);
		g[y].emplace_back(x);
	}
	bfs1();
	for (int i = n; i >= 1; i--) {
		int u = order[i];	sz[u] = 1;
		for (auto v : g[u]) {
			if (par[v] == u) {
				sz[u] += sz[v];
			}
		}
	}
	for (int u = 1; u <= n; u++) {
		for (auto v : g[u]) {
			if (v != par[u] && u != par[v]) {
				special[++nodes] = u;
				bfs(nodes, u);
				break;
			}
		}
	}
	dfs(1);
	int ans = n;
	for (int i = 2; i <= n; i++) {
		calc(i, 1, i);
		for (int j = 1; j <= nodes; j++) {
			calc(special[j], dist[j][i], i);
		}
	}
	dfs2(1);
	dfs3(1);
	static int tmp[202], tmpl;
	for (int i = 2; i <= n; i++) {
		int res = n, t = 0;
		tmpl = 0;
		for (auto j : v[i]) {
			tmp[tmpl++] = j;
		}
		while (t < tmpl) {
			int now = t;
			while (t < tmpl && L[tmp[now]] <= L[tmp[t]] && L[tmp[t]] <= R[tmp[now]]) {
				++t;
			}
			res -= sz[tmp[now]];
		}
		cmin(ans, res);
	}
	std::cout << ans << "\n";
	return 0;
}
上一篇:codeforces 600E - Lomsat gelral (dsu on tree)


下一篇:HDU-1213 How Many Tables