Loading

[Ynoi2008] rdCcot 做题记录

link

考虑对于每个连通块,我们寻找一个代表元计数。

可以设定为深度最小的点,若深度同样小,则选定编号更小的。我们对于每个点 \(u\) 求出 \(l_u, r_u\) 表示根据上述比较规则下比 \(u\) 小,且距离不超过 \(C\),最接近 \(u\) 的一左一右两个点。如果 \(l_u, r_u\) 任意一个点存在当前询问区间中则 \(u\) 不是代表元,所以统计 \(l_u < l \le u \le r < r_u\)\(u\) 个数即可。

正确性只需证明非代表元的 \(l_u, r_u\) 一定有一个在 \([l, r]\) 中,反证,\(u\) 只和在上述比较规则小比他大的点 C - 连通,那么这些点一定也达到不了其他点,这与 \(u\) 是非代表元矛盾。

考虑点分治,按距离依次加入所有点,用线段树二分求出与某个位置最近的一左一右两个位置。最后做一个二维数点即可。

  • 启示:设定代表元
点击查看代码
#include <bits/stdc++.h>

namespace Initial {
	#define ll int
	#define ull unsigned long long
	#define fi first
	#define se second
	#define mkp make_pair
	#define pir pair <ll, ll>
	#define pb emplace_back
	#define i128 __int128
	using namespace std;
	const ll maxn = 6e5 + 10, inf = 1e9, mod = 1e9 + 7;
	ll power(ll a, ll b = mod - 2) {
		ll s = 1;
		while(b) {
			if(b & 1) s = 1ll * s * a %mod;
			a = 1ll * a * a %mod, b >>= 1;
		} return s;
	}
	template <class T>
	const ll pls(const T x, const T y) { return x + y >= mod? x + y - mod : x + y; }
	template <class T>
	void add(T &x, const T y) { x = x + y >= mod? x + y - mod : x + y; }
	template <class T>
	void chkmax(T &x, const T y) { x = x < y? y : x; }
	template <class T>
	void chkmin(T &x, const T y) { x = x > y? y : x; }
} using namespace Initial;

namespace IO {
	char buf[1 << 22], *p1 = buf, *p2 = buf;
//	#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, (1 << 22) - 10, stdin), p1 == p2)? EOF : *p1++)
	template <class T>
	void rd(T &x) {
		char ch; bool f = 0;
		while(!isdigit(ch = getchar()));
			if(ch == '-') f = 1;
		x = ch - '0';
		while(isdigit(ch = getchar()))
			x = (x << 1) + (x << 3) + ch - '0';
		if(f) x = -x;
	} char obuf[1 << 22], *O = obuf;
	void putc(const char ch) { *O++ = ch; }
	void write(ll x) {
		if(x < 0) *O++ = '-', x = -x;
		if(x > 9) write(x / 10);
		*O++ = x % 10 + '0';
	}
	void write(const ll x, const char ch) { write(x), putc(ch); }
	void flush() { fwrite(buf, O - buf, 1, stdout); }
} using IO::rd; using IO::write; 

ll n, m, C, l[maxn], r[maxn], dep[maxn], id[maxn], w[maxn];
vector <ll> to[maxn];
void getdep(ll u, ll fa = 0) {
	dep[u] = dep[fa] + 1;
	for(ll v: to[u])
		if(v ^ fa) getdep(v, u);
}

namespace centroid_divide {
	struct SGT {
		ll mn[maxn << 2];
		const void modify(const ll p, const ll l, const ll r, const ll x) {
			mn[p] = min(mn[p], w[x]); if(l == r) return;
			const ll mid = l + r >> 1;
			if(x <= mid) modify(p << 1, l, mid, x);
			else modify(p << 1|1, mid + 1, r, x);
		}
		const ll queryl(const ll p, const ll l, const ll r, const ll x) {
			if(l > x || mn[p] >= w[x]) return 0;
			if(l == r) return l; const ll mid = l + r >> 1;
			const ll c = queryl(p << 1|1, mid + 1, r, x);
			if(c) return c;
			return queryl(p << 1, l, mid, x);
		}
		const ll queryr(const ll p, const ll l, const ll r, const ll x) {
			if(r < x || mn[p] >= w[x]) return n + 1;
			if(l == r) return l; ll mid = l + r >> 1;
			ll c = queryr(p << 1, l, mid, x);
			if(c <= n) return c;
			return queryr(p << 1|1, mid + 1, r, x);
		}
		const void clr(const ll p, const ll l, const ll r) {
			if(mn[p] >= inf) return; mn[p] = inf;
			if(l == r) return; ll mid = l + r >> 1;
			clr(p << 1, l, mid), clr(p << 1|1, mid + 1, r);
		}
	} tr;
	ll bs, rt, siz[maxn]; bool vis[maxn];
	void findrt(ll u, ll N, ll fa = 0) {
		siz[u] = 1; ll mx = 0;
		for(ll v: to[u])
			if(v != fa && !vis[v]) {
				findrt(v, N, u), siz[u] += siz[v];
				mx = max(mx, siz[v]);
			} mx = max(mx, N - siz[u]);
		if(mx < bs) bs = mx, rt = u;
	} ll dis[maxn], len; pir vertice[maxn];
	void dfs(ll u, ll fa = 0) {
		siz[u] = 1, vertice[++len] = mkp(dis[u], u);
		for(ll v: to[u])
			if(v != fa && !vis[v]) {
				dis[v] = dis[u] + 1, dfs(v, u);
				siz[u] += siz[v];
			}
	}
	void solve(ll u, ll N) {
		bs = inf, findrt(u, N); len = 0;
		vis[u = rt] = true, dis[u] = 0, dfs(u);
		sort(vertice + 1, vertice + 1 + len), tr.clr(1, 1, n);
		for(ll i = len, j = 1; i; i--) {
			ll x = vertice[i].se, y;
			while(j <= len && dis[y = vertice[j].se] + dis[x] <= C)
			 	tr.modify(1, 1, n, y), ++j;
			chkmax(l[x], tr.queryl(1, 1, n, x));
			chkmin(r[x], tr.queryr(1, 1, n, x));
		}
		for(ll v: to[u])
			if(!vis[v]) solve(v, siz[v]);
	}
}

struct _BIT {
	ll dat[maxn];
	void add(ll x, ll v) {
		for(; x <= n; x += x & -x) dat[x] += v;
	}
	ll ask(ll x) {
		ll v = 0;
		for(; x; x -= x & -x) v += dat[x];
		return v;
	}
} BIT; ll ans[maxn]; pir ff[maxn];
struct qur { ll l, r, id; } q[maxn];

int main() {
	rd(n), rd(m), rd(C);
	for(ll i = 2, x; i <= n; i++)
		rd(x), to[x].pb(id[i] = i), to[i].pb(x); getdep(1);
	sort(id + 1, id + 1 + n, [](ll x, ll y) {
		return dep[x] ^ dep[y]? dep[x] < dep[y] : x < y;
	});
	for(ll i = 1; i <= n; i++) w[id[i]] = i;
	for(ll i = 1; i <= n; i++) r[i] = n + 1;
	centroid_divide::solve(1, n);
	for(ll i = 1; i <= n; i++) ff[i] = mkp(r[i], l[i]);
	sort(ff + 1, ff + 1 + n);
	for(ll i = 1, l, r; i <= m; i++)
		rd(q[i].l), rd(q[i].r), q[i].id = i;
	sort(q + 1, q + 1 + m, [](const qur a, const qur b) {
		return a.r < b.r;
	});
	for(ll i = 1, j = 0, k = 0; i <= n; i++) {
		BIT.add(l[i] + 1, 1);
		while(j < n && ff[j + 1].fi == i) BIT.add(ff[++j].se + 1, -1);
		while(k < m && q[k + 1].r == i) ++k, ans[q[k].id] = BIT.ask(q[k].l);
	} BIT = {};
	sort(q + 1, q + 1 + m, [](const qur a, const qur b) {
		return a.l < b.l;
	});
	for(ll i = 1, j = 0; i <= n; i++) {
		while(j < m && q[j + 1].l == i)
			++j, ans[q[j].id] -= BIT.ask(n - q[j].r + 1);
		BIT.add(n - r[i] + 2, 1);
	}
	for(ll i = 1; i <= m; i++) printf("%d\n", ans[i]);
	return 0;
}
posted @ 2024-12-13 20:39  Sktn0089  阅读(25)  评论(0)    收藏  举报