[USACO18JAN]Lifeguards P(构造+点分治)

[USACO18JAN]Lifeguards P(构造+点分治)

题目大意

贝茜被农民们逼进了一个偏僻的农场。农场可视为一棵有 (N) 个结点的树,结点分别编号为 (1,2,ldots, N) 。每个叶子结点都是出入口。开始时,每个出入口都可以放一个农民(也可以不放)。每个时刻,贝茜和农民都可以移动到相邻的一个结点。如果某一时刻农民与贝茜相遇了(在边上或点上均算),则贝茜将被抓住。抓捕过程中,农民们与贝茜均知道对方在哪个结点。

请问:对于结点 (i\,(1le ile N)) ,如果开始时贝茜在该结点,最少有多少农民,她才会被抓住。

数据范围

(2 leq N leq 7 cdot 10^4)

解题思路

神题++ 贝西贝西贝西呦

(deg[x],~d[x],~dep[x]) 分别指 x 的度数,x 距离叶子节点的最短距离,以 rt 为根时,x 的深度

容易发现贝西在点 x 被截住的条件是 (d[x] <= dep[x]) 且 贝西没在 x 父亲处被截住,那么 x 对答案的贡献为 1。暴力 dfs 是 (Theta(n^2))

构造,发现 x 满足截住条件的话它的子树都会满足条件,让整个子树都产生贡献并且贡献之和为 1,即 ((sum_{iin subtree(x)}val[i]) = 1),又因为 ((sum_{i in subtree(x)}deg[i]) = 2 cdot m-1),那么 (val[x] = 2 - deg[x]) 即可

于是可以点分治 (ans[x] = sum_{i = 1}^n [dist(x, i) >= d[i]] * (2-deg[i])),利用单调性点分治 + 排序即可

时间复杂度 (T(N) = 2 * T(frac N2) + NlogN = Nlog^2N)

#include <queue>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MP make_pair
#define ll long long
#define fi first
#define se second
using namespace std;

template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
    for (;isdigit(c);c=getchar()) x=x*10+(c^48);
    if (f) x=-x;
}

template<typename F>
inline void write(F x)
{
	static short st[30];short tp=0;
	if(x<0) putchar('-'),x=-x;
	do st[++tp]=x%10,x/=10; while(x);
	while(tp) putchar('0'|st[tp--]);
	putchar('
');
}

template <typename T>
inline void Mx(T &x, T y) { x < y && (x = y); }

template <typename T>
inline void Mn(T &x, T y) { x > y && (x = y); }

const int N = 200500;
int deg[N], d[N], h[N], ne[N], to[N], tot;
inline void add(int x, int y) {
	ne[++tot] = h[x], deg[to[h[x] = tot] = y]++;
}


void Dfs(int x, int fa) {
	if (deg[x] == 1) d[x] = 0;
	for (int i = h[x]; i; i = ne[i]) {
		int y = to[i]; if (y == fa) continue;
		Dfs(y, x); Mn(d[x], d[y] + 1);
	}
}

void Dfs(int x, int fa, int mn) {
	Mn(mn, d[x]), Mn(d[x], mn);
	for (int i = h[x]; i; i = ne[i]) 
		if (to[i] != fa) Dfs(to[i], x, mn + 1);
}

int ans[N], vis[N], siz[N], sz, mn, rt, n;

void get_rt(int x, int fa) {
	siz[x] = 1; int mx = 0;
	for (int i = h[x]; i; i = ne[i]) {
		int y = to[i]; if (vis[y] || y == fa) continue;
		get_rt(y, x); siz[x] += siz[y]; Mx(mx, siz[y]);
	}
	Mx(mx, sz - siz[x]);
	if (mx < mn) mn = mx, rt = x;
}



int sam[N], bl[N], sum, tmp, t1, t2;
pair<int, int> A[N], B[N];
void get(int x, int fa, int dep) {
	bl[x] = tmp;
	A[++t1] = MP(dep, x), B[++t2] = MP(d[x] - dep, x);
	for (int i = h[x]; i; i = ne[i]) {
		int y = to[i]; 
		if (vis[y] || y == fa) continue;
		get(y, x, dep + 1);
	}
}

void solve(int x) {
	vis[bl[x] = x] = 1, sam[x] = 0, t1 = t2 = 0;
	A[++t1] = MP(0, x), B[++t2] = MP(d[x], x);
	for (int i = h[x]; i; i = ne[i])
		if (!vis[tmp = to[i]]) sam[tmp] = 0, get(tmp, x, 1);
	sort(A + 1, A + t1 + 1), sort(B + 1, B + t2 + 1);
	
	ll sum = 0, j = 0;
	for (int i = 1;i <= t1; i++) {
		while (j < t1 && B[j+1].fi - A[i].fi <= 0) 
			++j, sum += 2 - deg[B[j].se], sam[bl[B[j].se]] += 2 - deg[B[j].se];
		ans[A[i].se] += sum - sam[bl[A[i].se]];
	}
	
	for (int i = h[x]; i; i = ne[i]) {
		int y = to[i]; if (vis[y]) continue;
		sz = siz[rt = y], mn = n, get_rt(y, 0);
		solve(rt);
	}
}

int main() {
	read(n);
	for (int i = 1, x, y; i < n ; i++)
		read(x), read(y), add(x, y), add(y, x);
	memset(d, 0x3f, sizeof(d));
	Dfs(1, 0), Dfs(1, 0, 1e8);
	rt = 1, sz = mn = n; get_rt(1, 0), solve(rt);
	for (int i = 1;i <= n; i++)
		write(deg[i] == 1 ? 1 : ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/Hs-black/p/12830682.html