洛谷9695 [GDCPC 2023] Traveling in Cells 题解(线段树+二分)

考虑对于一个给定的颜色集合 \(S\),我们可达的位置一定是一个区间 \([L,R]\)。于是考虑怎么求出 \(L,R\) 即可。

考虑二分,现在问题转换成判定一个区间 \([x,R]\)(区间 \([L,x]\) 同理)是否所有颜色都在我们的集合 \(S\) 中。

考虑对每一个颜色开一个线段树。区间 \([x,R]\) 里的每个颜色都在集合 \(S\) 中,等价于 \(S\) 中所有颜色在 \([x,R]\) 里的出现次数之和为 \(R-x+1\)

时间复杂度 \(O(n\log^2 n)\),如果实现的精细一点用线段树上二分可以做到 \(O(n \log n)\)

const int MAXN = 1e5 + 5;
int n, q, c[MAXN], v[MAXN];

struct _sgt {
	struct _node {
		int v, ls, rs;
	} tr[MAXN << 6];
	int tot;

	void pushup(int p) {
		tr[p].v = tr[tr[p].ls].v + tr[tr[p].rs].v;
	}
 
	void modify(int &p, int l, int r, int k, int v) {
		if (!p) p = ++tot;
		if (l == r) return tr[p].v += v, void();
		if (k <= mid) modify(tr[p].ls, l, mid, k, v);
		else modify(tr[p].rs, mid + 1, r, k, v);
		pushup(p);
	}

	int query(int p, int l, int r, int L, int R) {
		if (!p) return 0;
		if (L <= l && r <= R) return tr[p].v;
		int res = 0;
		if (L <= mid) res += query(tr[p].ls, l, mid, L, R);
		if (mid < R) res += query(tr[p].rs, mid + 1, r, L, R);
		return res;
	}

	void clear(int p) {
		if (tr[p].ls) clear(tr[p].ls);
		if (tr[p].rs) clear(tr[p].rs);
		tr[p].v = tr[p].ls = tr[p].rs = 0;
	}
} t;
int rt[MAXN];

int solveR(int x, int k, vector<int> a) {
	int l = x, r = n + 1;
	while (l + 1 < r) {
		int sum = 0;
		for (int i = 0; i < k; ++i)
			sum += t.query(rt[a[i]], 1, n, x, mid);
		if (sum == (mid - x + 1)) l = mid;
		else r = mid;
	}
	return l;
}

int solveL(int x, int k, vector<int> a) {
	int l = 0, r = x;
	while (l + 1 < r) {
		int sum = 0;
		for (int i = 0; i < k; ++i)
			sum += t.query(rt[a[i]], 1, n, mid, x);
		if (sum == (x - mid + 1)) r = mid;
		else l = mid;
	}
	return r;
}

struct _bit {
	int tr[MAXN];
	int lowbit(int x) { return x & (-x); }
	void modify(int x, int v) {
		while (x <= n) {
			tr[x] += v;
			x += lowbit(x);
		}
	}
	int query(int x) {
		int res = 0;
		while (x) {
			res += tr[x];
			x -= lowbit(x);
		}
		return res;
	}
} bit;

void work() {
	cin >> n >> q;
	for (int i = 1; i <= n; ++i)
		cin >> c[i];
	for (int i = 1; i <= n; ++i)
		cin >> v[i];
	for (int i = 1; i <= n; ++i) {
		t.modify(rt[c[i]], 1, n, i, 1);
		bit.modify(i, v[i]);
	}
	while (q--) {
		int op; cin >> op;
		if (op == 1) {
			int p, x; cin >> p >> x;
			t.modify(rt[c[p]], 1, n, p, -1);
			t.modify(rt[x], 1, n, p, 1);
			c[p] = x;
		} else if (op == 2) {
			int p, x; cin >> p >> x;
			bit.modify(p, x - v[p]);
			v[p] = x;
		} else {
			int x, k; cin >> x >> k;
			vector<int> a(k);
			for (int i = 0; i < k; ++i)
				cin >> a[i];
			int L = solveL(x, k, a), R = solveR(x, k, a);
			cout << bit.query(R) - bit.query(L - 1) << endl;
		}
	}

	for (int i = 1; i <= n; ++i) {
		t.clear(rt[i]);
		bit.tr[i] = 0;
	}
	fill(rt, rt + 1 + n, 0ll);
	t.tot = 0;
}
posted @ 2025-10-08 10:41  小蛐蛐awa  阅读(11)  评论(0)    收藏  举报