Loading

[Ynoi2011] 成都七中 做题记录

Educational。link

连通块问题不强于路径统计问题,考虑点分治,对于每个分治点统计所有包含该点的连通块。

判断一个连通块是否包含一个分治点是容易的,DFS 一遍判断路径上最大最小值是否超出限制。

DFS 可以求出所有点到分治点的路径上的最大最小值,视作一个区间 \([mn_i, mx_i]\),颜色为 \(c_i\)。问题转化为多次询问,每次求 \([l, r]\) 包含的所有区间颜色数量。

这是容易的,对 \(r\) 扫描线,每个颜色维护最大左端点,使用树状数组查询,时间复杂度 \(\mathcal O(n\log ^ 2n)\)

  • 启示:点分治统计连通块 / 求解连通块问题
点击查看代码
#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 = 1e5 + 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 Read {
	char buf[1 << 22], *p1, *p2;
	#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;
	}
} using Read::rd;

ll n, m, a[maxn], qL[maxn], qR[maxn], ans[maxn], tree[maxn];
vector <ll> to[maxn]; ll bs, rt, siz[maxn], l[maxn], r[maxn];

void tr_add(ll x, ll v) {
	for(; x <= n; x += x & -x) tree[x] += v; 
}
ll tr_ask(ll x) {
	ll v = 0;
	for(; x; x -= x & -x) v += tree[x];
	return v;
}

bool vis[maxn], isans[maxn]; ll cl[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;
}
struct Data { ll l, r, c; }; vector <Data> col, qur[maxn], _qur;
const bool operator < (const Data a, const Data b) { return a.r < b.r; }
void dfs(ll u, ll fa = 0) {
	siz[u] = 1, chkmin(l[u], u), chkmax(r[u], u);
	for(Data t: qur[u])
		if(!isans[t.c] && t.l <= l[u] && r[u] <= t.r)
			isans[t.c] = true, _qur.pb(t);
	col.pb((Data) { l[u], r[u], a[u] });
	for(ll v: to[u])
		if(v != fa && !vis[v]) {
			l[v] = l[u], r[v] = r[u], dfs(v, u);
			siz[u] += siz[v];
		}
}
void solve(ll u, ll N) {
	bs = inf, findrt(u, N);
	vis[u = rt] = true, col.clear(), _qur.clear();
	l[u] = r[u] = u, dfs(u);
	sort(col.begin(), col.end()), sort(_qur.begin(), _qur.end());
	for(ll i = 0, j = 0; i < _qur.size(); i++) {
		Data now = _qur[i], t;
		while(j < col.size() && (t = col[j]).r <= now.r) {
			if(cl[t.c] < t.l)
				tr_add(n - cl[t.c] + 1, -1), tr_add(n - (cl[t.c] = t.l) + 1, 1);
			++j;
		} ans[now.c] = tr_ask(n - now.l + 1);
	}
	for(Data t: col)
		if(cl[t.c]) tr_add(n - cl[t.c] + 1, -1), cl[t.c] = 0;
	for(ll v: to[u])
		if(!vis[v]) solve(v, siz[v]);
} 

int main() {
	rd(n), rd(m);
	for(ll i = 1; i <= n; i++) rd(a[i]);
	for(ll i = 1, u, v; i < n; i++) {
		rd(u), rd(v);
		to[u].pb(v), to[v].pb(u);
	}
	for(ll i = 1, l, r, x; i <= m; i++) {
		rd(l), rd(r), rd(x);
		qur[x].pb((Data) { l, r, i });
	}
	solve(1, n);
	for(ll i = 1; i <= m; i++) printf("%d\n", ans[i]);
	return 0;
}
posted @ 2024-12-13 20:14  Sktn0089  阅读(22)  评论(0)    收藏  举报