[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;
}

浙公网安备 33010602011771号