2025CSP-S模拟赛16 比赛总结

2025CSP-S模拟赛16

T1 醉

简单题。也是场切了。

首先考虑答案是否存在。根据一个性质叫做一个点在树上离他最远的节点一定是直径的端点。记直径为端点分别为 \(U,V\)。然后分别算一下点 \(u\)\(U,V\) 的距离是否 \(\geq d\) 即可。

考虑存在答案,那么不妨设 \(dis(u,U) \geq d\),则点 \(v\) 一定在 \(u\)\(U\) 的这条路径上。然后就做完了。求出 \(u\)\(U\) 的 lca 记为 \(lca\),判断 \(v\)\(u,lca\) 的路径上还是在 \(U,lca\) 的路径上,然后跳 \(k\) 级祖先就行了。

#include <bits/stdc++.h>

using namespace std;

int read() {
	int x = 0; char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x;
}
const int N = 2e5 + 10;
int n, m;
vector<int> G[N];
int dep[N], fa[N][22];
int U, V, dd[N];
void dfs1(int x, int fr) {
	dep[x] = dep[fr] + 1;
	if (dep[x] > dep[U]) U = x;
	fa[x][0] = fr;
	for (int i = 1; i <= 20; i++) {
		fa[x][i] = fa[fa[x][i - 1]][i - 1];
	}
	for (int y : G[x]) {
		if (y == fr) continue;
		dfs1(y, x);
	}
}
void dfs2(int x, int fr) {
	dd[x] = dd[fr] + 1;
	if (dd[x] > dd[V]) V = x;
	for (int y : G[x]) {
		if (y == fr) continue;
		dfs2(y, x);
	}
}
int getlca(int x, int y) {
	if (dep[x] < dep[y]) swap(x, y);
	for (int i = 20; i >= 0; i--) {
		if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
	}
	if (x == y) return x;
	for (int i = 20; i >= 0; i--) {
		if (fa[x][i] != fa[y][i]) {
			x = fa[x][i];
			y = fa[y][i];
		}
	}
	return fa[x][0];
}
inline int getdis(int x, int y) {
	return dep[x] + dep[y] - 2 * dep[getlca(x, y)];
}
int getfa(int x, int k) {
	for (int i = 0; i <= 20; i++) {
		if ((k >> i) & 1) {
			x = fa[x][i];
		}
	}
	return x;
}
int main() {
	n = read();
	for (int i = 1; i < n; i++) {
		int x = read(), y = read();
		G[x].push_back(y);
		G[y].push_back(x);
	}
	dfs1(1, 0);
	dfs2(U, 0);
	m = read();
	while (m--) {
		int u = read(), d = read();
		int d1 = getdis(u, U), d2 = getdis(u, V);
		if (d1 < d && d2 < d) {
			printf("-1\n");
			continue;
		}
		if (d1 >= d) {
			int lca = getlca(u, U);
			if (d <= dep[u] - dep[lca]) {
				printf("%d\n", getfa(u, d));
			} else {
				printf("%d\n", getfa(U, d1 - d));
			}
		} else {
			int lca = getlca(u, V);
			if (d <= dep[u] - dep[lca]) {
				printf("%d\n", getfa(u, d));
			} else {
				printf("%d\n", getfa(V, d2 - d));
			}
		}
	}
	
	return 0;
}

T2 与

首先,考虑答案如何求解。不难想到可以用如下方法求解:

for (int i = 1; i <= qq; i++) {
    int l = read(), r = read();
    int sum = a[l];
    for (int i = l + 1; i <= r; i++) {
        if (a[i] & sum) sum |= a[i];
    }
    if (a[r] & sum) printf("Shi\n");
    else printf("Fou\n");
}

然后发现这个满足结合律,考虑用线段树维护。

这个代码不难理解,直接看代码吧。。

#include <bits/stdc++.h>

using namespace std;

int read() {
	int x = 0; char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') {
		x = (x << 1) + (x << 3) + (ch ^ 48);
		ch = getchar();
	}
	return x;
}
const int N = 3e5 + 10;
int n, qq, a[N];
struct node {
	int l, r, s[20];
} tree[4 * N];
#define lc p << 1
#define rc p << 1 | 1
void pushup(int p) {
	for (int i = 0; i < 20; i++) {
		tree[p].s[i] = tree[lc].s[i];
		for (int j = 0; j < 20; j++) {
			if ((1 << j) & tree[lc].s[i]) {
				tree[p].s[i] |= tree[rc].s[j];
			}
		}
		tree[p].s[i] |= tree[rc].s[i];
	}
}
void build(int p, int l, int r) {
	tree[p].l = l, tree[p].r = r;
	if (l == r) {
		for (int i = 0; i < 20; i++) {
			if ((1 << i) & a[l]) tree[p].s[i] = a[l];
		}
		return;
	}
	int mid = l + r >> 1;
	build(lc, l, mid), build(rc, mid + 1, r);
	pushup(p);
}
int sum;
bool query(int p, int l, int r, int v) {
	if (sum & v) return 1;
	if (l <= tree[p].l && tree[p].r <= r) {
		int x = 0;
		for (int i = 0; i < 20; i++) {
			if ((1 << i) & sum) x |= tree[p].s[i];
		}
		sum |= x;
		return sum & v;
	}
	int mid = tree[p].l + tree[p].r >> 1;
	int res = 0;
	if (l <= mid) res |= query(lc, l, r, v);
	if (res) return 1;
	if (mid < r) res |= query(rc, l, r, v);
	return res;
}
int main() {
	n = read(), qq = read();
	for (int i = 1; i <= n; i++) {
		a[i] = read();
	}
	build(1, 1, n);
	for (int i = 1; i <= qq; i++) {
		int l = read(), r = read();
		sum = a[l];
		if (query(1, l + 1, r - 1, a[r])) {
			printf("Shi\n");
		} else printf("Fou\n");
	}
	
	return 0;
}

T3 小恐龙

T4 愤怒的小 L

posted @ 2025-07-15 21:11  Zctf1088  阅读(25)  评论(0)    收藏  举报