CF1479D Odd Mineral Resource

CF1479D Odd Mineral Resource

CF1000F 上树,考虑树上莫队。

同理,对值域分块,记 sumisum_i 表示第 ii 块值域出现次数为奇数的数的个数,再开个桶记录一下每个数的出现次数就行了,单次修改 O(1)\mathcal O(1)

对于询问,同块暴力,否则从左散块,中整块,右散块判断,找到就结束,单次询问 O(n)\mathcal O(\sqrt n)

说下树上莫队的细节:

  • 建括号序,有两种情况,有一种需特判 LCA(树剖维护)。
  • 注意一些加加减减的细节问题,本人模拟赛因为这爆零。

综上,时间复杂度 O(nn)\mathcal O(n\sqrt n),空间复杂度 O(n)\mathcal O(n)nn 与值域同阶。

#include <bits/stdc++.h>

using namespace std;

#define he putchar('\n')
#define ha putchar(' ')

typedef long long ll;

inline int read() {
	int x = 0;
	char c = getchar();
	while (c < '0' || c > '9')
		c = getchar();
	while (c >= '0' && c <= '9')
		x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x;
}

inline void write(int x) {
	if (x < 0) {
		x = -x;
		putchar('-');
	}
	if (x > 9) write(x / 10);
	putchar(x % 10 + 48);
}

const int _ = 7e5 + 10;

int n, m, cnt, a[_], L[_], R[_], fn[_], ans[_];

int sq, bel[_];

vector<int> d[_];

void dfs(int u, int fa) {
	fn[++cnt] = u, L[u] = cnt;
	for (int v : d[u]) {
		if (v == fa) continue;
		dfs(v, u);
	}
	fn[++cnt] = u, R[u] = cnt;
}

int siz[_], dep[_], fa[_], hson[_], top[_];

void dfs1(int u, int D = 1) {
	siz[u] = 1, dep[u] = D;
	for (int v : d[u])
		if (!siz[v]) {
		fa[v] = u;
		dfs1(v, D + 1);
		siz[u] += siz[v];
		if (siz[hson[u]] < siz[v]) hson[u] = v;
	}
}

void dfs2(int u, int tf) {
	top[u] = tf;
	if (hson[u]) dfs2(hson[u], tf);
	for (int v : d[u])
		if (!top[v]) dfs2(v, v);
}

int LCA(int u, int v) {
	while (top[u] != top[v]) {
		if (dep[top[u]] < dep[top[v]]) swap(u, v);
		u = fa[top[u]];
	}
	return dep[u] > dep[v] ? v : u;
}

struct Query {
	int l, r, L, R, id, dd;
} q[_];

bool cmp(Query x, Query y) {
	if (bel[x.L] != bel[y.L]) return x.L < y.L;
	if (bel[x.L] & 1) return x.R < y.R;
	return x.R > y.R;
}

int t[_], sum[_], lp[_], rp[_];

void upd(int x) {
	if (t[x] & 1) sum[bel[x]]--;
	else sum[bel[x]]++;
	t[x] ^= 1;
}

signed main() {
	n = read(), m = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	for (int i = 1; i < n; ++i) {
		int x = read(), y = read();
		d[x].push_back(y), d[y].push_back(x);
	}
	dfs(1, 0);
	dfs1(1), dfs2(1, 1);
	sq = sqrt(cnt) * 1.2;
	for (int i = 1; i <= cnt; ++i) bel[i] = (i - 1) / sq + 1;
	for (int i = 1; i <= bel[cnt]; ++i) lp[i] = rp[i - 1] + 1, rp[i] = min(cnt, i * sq);
	for (int i = 1, u, v; i <= m; ++i) {
		u = read(), v = read();
		q[i].l = read(), q[i].r = read(), q[i].id = i;
		if (L[u] > L[v]) swap(u, v);
		if (R[u] < L[v]) q[i].L = R[u], q[i].R = L[v], q[i].dd = LCA(u, v);
		else q[i].L = L[u], q[i].R = L[v];
	}
	sort(q + 1, q + m + 1, cmp);
	int l = 0, r = 0;
	for (int i = 1; i <= m; ++i) {
		while (l > q[i].L) upd(a[fn[--l]]);
		while (r < q[i].R) upd(a[fn[++r]]);
		while (l < q[i].L) upd(a[fn[l++]]);
		while (r > q[i].R) upd(a[fn[r--]]);
		upd(a[fn[L[q[i].dd]]]);
		bool flg = 0;
		if (bel[q[i].l] == bel[q[i].r]) {
			for (int j = q[i].l; j <= q[i].r; ++j)
				if (t[j] & 1) {ans[q[i].id] = j, flg = 1;break;}
		} else {
			if (!flg) for (int j = q[i].l; j <= rp[bel[q[i].l]]; ++j) if (t[j] & 1) {ans[q[i].id] = j;flg = 1;break;}
			if (!flg) for (int j = bel[q[i].l] + 1; j <= bel[q[i].r] - 1; ++j) if (sum[j]) {
				for (int k = lp[j]; k <= rp[j]; ++k) if (t[k] & 1) {ans[q[i].id] = k;flg = 1;break;}
				if (flg) break;
			}
			if (!flg) for (int j = lp[bel[q[i].r]]; j <= q[i].r; ++j) if (t[j] & 1) {ans[q[i].id] = j;flg = 1;break;}
		}
		if (!flg) ans[q[i].id] = -1;
		upd(a[fn[L[q[i].dd]]]);
	}
	for (int i = 1; i <= m; ++i) write(ans[i]), he;
	return 0;
}
posted @ 2022-07-25 15:06  蒟蒻orz  阅读(4)  评论(0编辑  收藏  举报  来源