Loading

MX galaxy Day18

stream

\(m\) 条限制看做 \(x_i\leftrightarrow y_i\) 的一条权值为 \(z_i\) 的边。
对于每个连通块单独考虑,取连通块内编号最小的点作为根,处理出每个点与 \(rt\) 的异或值 \(y\)
假设合法。
然后每条限制形如 \(rt\oplus y\ge l\) 或者 \(rt\oplus y\le r\)
将这些限制分讨插入 \(Tire\) 树,暗位贪心。
具体的,如果我们要求 \(rt\oplus y \le r\) ,且 \(r\) 的最高位是 \(0\) ,那么当前位 \(rt\oplus y=1\) 的子树就被割掉了。
然后再在 \(Trie\) 树上找到一组字典序最小的合法解即可。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)

const int _ = 2e5 + 7;
const int V = 30;
typedef long long ll;

int c, T, n, m, l[_], r[_], dis[_], a[_]; bool vis[_];
int ch[_][2], idx; bool tag[_];
std::vector <int> e[_], g[_], rg;

bool dfs(int u) {
	rg.push_back(u), vis[u] = true;
	lep(k, 0, (int)e[u].size() - 1) { int v = e[u][k], w = g[u][k];
		if (!vis[v]) {
			dis[v] = (dis[u] ^ w);
			if (!dfs(v)) return false;
		}
		else if (dis[v] != (dis[u] ^ w)) return false;
	}
	return true;
}
int rc() { ++idx; ch[idx][0] = ch[idx][1] = tag[idx] = 0; return idx; }
void ins(int y, int v, int op) {
	int x = 0;
	rep(k, V, 0) { int _y = (y >> k) & 1, _v = (v >> k) & 1;
		if (tag[x]) return;
		if (op == 0) {
			if (!ch[x][_y]) ch[x][_y] = rc();
			if (!_v) x = ch[x][_y];
			else {
				tag[ch[x][_y]] = true;
				if (!ch[x][1 ^ _y]) ch[x][1 ^ _y] = rc();
				x = ch[x][1 ^ _y];
			}
		}
		else {
			if (!ch[x][1 ^ _y]) ch[x][1 ^ _y] = rc();
			if (_v) x = ch[x][1 ^ _y];
			else {
				tag[ch[x][1 ^ _y]] = true;
				if (!ch[x][_y]) ch[x][_y] = rc();
				x = ch[x][_y];
			}
		}
	}
}
bool get(int u, int x, int d) {
	if (d == -1 or !ch[x][0]) return true;
	if (tag[ch[x][0]] or !get(u, ch[x][0], d - 1)) {
		if (tag[ch[x][1]]) return false;
		a[u] |= (1 << d); if (!ch[x][1]) return true;
		if (get(u, ch[x][1], d - 1)) return true;
		else return a[u] ^= (1 << d), false;
	}
	return true;
}
bool Solve(int u) { rg.clear();
	if (!dfs(u)) return false;
	idx = -1, rc();
	for (int v : rg) ins(dis[v], l[v], 0), ins(dis[v], r[v], 1);
	if (!get(u, 0, V)) return false;
	for (int v : rg) a[v] = (a[u] ^ dis[v]);
	return true;
}

int main() {
#ifndef DEBUG
	freopen("stream.in", "r", stdin);
	freopen("stream.out","w",stdout);
#endif
	scanf("%d%d", & c, & T);
	while (T--) {
		scanf("%d%d", & n, & m); int u, v, w;
		lep(i, 1, n) scanf("%d%d", l + i, r + i);
		lep(i, 1, m) {
			scanf("%d%d%d", & u, & v, & w);
			e[u].push_back(v), g[u].push_back(w);
			e[v].push_back(u), g[v].push_back(w);
		}
		bool nt = false;
		lep(i, 1, n) if (!vis[i] and !Solve(i)) { nt = true; break; }
		if (nt) puts("-1");
		else { lep(i, 1, n) printf("%d ", a[i]); puts(""); }
		
		lep(i, 1, n) e[i].clear(), g[i].clear(), dis[i] = vis[i] = a[i] = 0;
	}
	return 0;
}

场切,爽。
可以发现对于某些 '\(h'\) 字符,可能会在某个时刻被激活,然后每个时刻向左生产一个 \('s'\)
可以倒序处理出激活时间,然后我们就可以直接扫原序列,找到第一个 \(\ge x\) 的位置,然后分讨输出。
优化直接线段树二分维护这个式子。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = a; i <= b; ++i)
#define rep(i, a, b) for (int i = a; i >= b; --i)

const int _ = 2e5 + 7;
typedef long long ll;
typedef std::pair<ll, int> PLI;

struct node { int i, x, k; };
int c, T, n, q, tm[_]; char s[_], ans[_];
ll sum[_ << 2], tot[_ << 2];
std::vector<node> o[_];
std::vector <int> l[_];

void prt(ll res, int i, int x, int k, int q) {
	if (res >= k) {
		if (s[i] == 'i') {
			if (tm[i - 1] and x >= tm[i - 1] - 1) ans[q] = 'e';
			else ans[q] = 'i';
		}
		else if (s[i] == 's') {
			if (i > 2 and tm[i - 2] == tm[i] + 2 and x >= tm[i - 2] - 1) ans[q] = 'r';
			else ans[q] = 's';
		}
		else {
			if (i > 2 and tm[i - 2] == tm[i] + 2 and x >= tm[i - 2] - 1 and
				(tm[i] ? res - (x - tm[i] + 1) : res) == k) ans[q] = 'r';
			else if (res == k) ans[q] = s[i];
			else ans[q] = 's';
		}
	}
	else ans[q] = '0';
}
#define ls p << 1
#define rs p << 1 | 1
#define md ((s + t) >> 1)
void mdy(int d, int x, int y, int s, int t, int p) {
	tot[p] += x, sum[p] += y; if (s == t) return; 
	d <= md ? mdy(d, x, y, s, md, ls) : mdy(d, x, y, md + 1, t, rs);
}
PLI qry(ll x, int k, int s, int t, int p) {
	if (s == t) return { (x + 1) * tot[p] + 1 - sum[p], s };
	ll tmp = (x + 1) * tot[ls] - sum[ls] + (md - s + 1);
	if (tmp >= k) return qry(x, k, s, md, ls);
	auto nw = qry(x, k - tmp, md + 1, t, rs);
	nw.first += tmp; return nw;
}
#undef ls
#undef rs
#undef md
void Mdy(int d, int x, int y) { mdy(d, x, y, 1, n, 1); }
PLI Qry(int x, int k) { return qry(x, k, 1, n, 1); }

int main() {
#ifndef DEBUG
	freopen("right.in", "r", stdin);
	freopen("right.out","w",stdout);
#endif

	scanf("%d%d", & c, & T);
	while (T--) {
		scanf("%d%d%s", & n, & q, s + 1);
		rep(i, n - 1, 1) {
			if (s[i] == 'h') {
				if (s[i + 1] == 'e') tm[i] = 1;
				else if (s[i + 1] == 'i') {
					if (i + 2 <= n and s[i + 2] == 's') tm[i] = 2;
					else if (tm[i + 2]) tm[i] = tm[i + 2] + 2;
				}
			}
		}
		lep(i, 1, n) if (tm[i]) l[tm[i]].push_back(i);
		int x, k;
		lep(Q, 1, q) {
			scanf("%d%d", & x, & k);
			if (x > n) o[n + 1].push_back({Q, x, k});
			else o[x].push_back({Q, x, k});
		}
		
		lep(i, 1, n + 1) {
			for (int v : l[i]) Mdy(v, 1, tm[v]);
			for (auto t : o[i]) {
				auto nw = Qry(t.x, t.k);
				prt(nw.first, nw.second, t.x, t.k, t.i);
			}
			l[i].clear(), o[i].clear();
		}
		lep(i, 1, q) putchar(ans[i]), putchar('\n');
		lep(i, 1, n) tm[i] = 0;
		lep(i, 1, 4 * n) sum[i] = tot[i] = 0;
	}
	return 0;
}

posted @ 2025-07-31 21:59  qkhm  阅读(11)  评论(0)    收藏  举报