这是一个很菜的 Oier 的博客|

Hanx16Msgr

园龄:2年8个月粉丝:12关注:3

2023-09-26 12:09阅读: 25评论: 0推荐: 0

P5838 [USACO19DEC] Milk Visits G

P5838 [USACO19DEC] Milk Visits G

Luogu P5838

Solution

提供一种奇特的 O(nnlognω) 的做法。

树链剖分转化成序列问题。然后变成了询问一个区间 l,r 是否存在一个颜色 k,显然可以 O(n) 预处理 O(n) 判定,这样复杂度是 O(nnlogn) 的,空间复杂度 O(nn),很卡,没敢写。

注意到并不需要数颜色出现了多少次,因此考虑使用 bitset 维护一个颜色是否出现。

对于整块,开 O(n)bitset,其中第 ibitset 的第 j 位表示颜色 i 是否在第 j 块出现。那么对于整块,可以使用 bitset 的位运算在 O(nω) 的时间内判定。

对于散块,考虑对每个块中的每一个颜色开一个长度为块长的 bitset ,第 i 位表示这个颜色在这个块中从左起的第 i 个位置出现了,那么询问也容易使用 bitset 的位运算做到 O(nω)。乍一看这部分的 bitset 大小是 O(n2ω) 的,但是因为一个块中的颜色数量是 O(n) 的,所以可以将这个块内的颜色重新映射到 [1,n] 的范围(类似于离散化),然后空间复杂度就降为了 O(nnω)。颜色在每个块内的离散化可以使用 Hash 表做到线性处理。

总时间复杂度 O(nnlognω),空间复杂度 O(nnω)

#include<bits/stdc++.h>
#define For(i, a, b) for (int i = (a); i <= (b); ++i)
#define Rof(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
using i64 = long long;
constexpr int _N = 1e5 + 5, _B = 400 + 5;
bool ST;
int n, m;
vector<int> e[_N];
int dep[_N], fa[_N], id[_N], son[_N];
int top[_N], siz[_N], dfn;
int a[_N], b[_N];
void Dfs1(int x, int F) {
	dep[x] = dep[F] + 1, fa[x] = F, siz[x] = 1;
	int maxson = -1;
	for (int v : e[x]) if (v != F) {
		Dfs1(v, x);
		if (siz[v] > maxson) maxson = siz[v], son[x] = v;
		siz[x] += siz[v];
	}
}
void Dfs2(int x, int topf) {
	id[x] = ++dfn, top[x] = topf, b[dfn] = a[x];
	if (son[x]) Dfs2(son[x], topf);
	for (int v : e[x]) if (v != son[x] && v != fa[x])
		Dfs2(v, v);
}
int pos[_N], bl[_N], br[_N], len, cnt;
bitset<_B> ct[_N], tl[_B], bct[_B][_B];
int tot[_B];
#include<ext/pb_ds/assoc_container.hpp>
__gnu_pbds::gp_hash_table<int, int> H[_B];
bool ED;
void InitBlock() {
	len = sqrt(n), cnt = (n - 1) / len + 1;
	For(i, 1, cnt) bl[i] = br[i - 1] + 1, br[i] = min(i * len, n);
	For(i, 1, cnt) tl[i] = tl[i - 1], tl[i].set(i);
	For(i, 1, cnt) {
		For(j, bl[i], br[i]) {
			pos[j] = i;
			ct[b[j]].set(i);
			if (H[i].find(b[j]) == H[i].end())
				H[i][b[j]] = ++tot[i];
			int nc = H[i][b[j]];
			bct[i][nc].set(j - bl[i] + 1);
		}
	}
}
bool AskB(int id, int l, int r, int k) {
	if (H[id].find(k) == H[id].end()) return 0;
	int nc = H[id][k];
	return ((bct[id][nc] >> (l - bl[id])) & tl[r - l + 1]).any();
}
bool Query(int l, int r, int k) {
	if (pos[l] == pos[r])
		return AskB(pos[l], l, r, k);
	else
		return AskB(pos[l], l, br[pos[l]], k)
			|| AskB(pos[r], bl[pos[r]], r, k)
			|| ((ct[k] >> pos[l]) & tl[pos[r] - pos[l] - 1]).any();
}
bool QueryPath(int x, int y, int k) {
	bool res = 0;
	while (top[x] != top[y]) {
		if (dep[top[x]] < dep[top[y]]) swap(x, y);
		res = Query(id[top[x]], id[x], k);
		if (res) return res;
		x = fa[top[x]];
	}
	if (dep[x] > dep[y]) swap(x, y);
	return Query(id[x], id[y], k);
}
signed main() {
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n >> m;
	For(i, 1, n) cin >> a[i];
	For(i, 2, n) {
		int x, y;
		cin >> x >> y;
		e[x].push_back(y);
		e[y].push_back(x);
	}
	Dfs1(1, 0), Dfs2(1, 1);
	InitBlock();
	For(i, 0, m - 1) {
		int x, y, k;
		cin >> x >> y >> k;
		cout << QueryPath(x, y, k);
	}
}
posted @   Hanx16Msgr  阅读(25)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起