[赛记] 暑假集训CSP提高模拟15

原题还是没找

串串 49pts

用的 $ manacher $,板子差点没打对,但好歹还是打对了。。。

赛时写的时候没有考虑到不用管偶回文,导致递归的时候有点问题。。。

其实根本用不到递归,将循环顺序改为倒序即可;

有三种情况:

  1. 回文半径 + 位置能够到达右端点;

显然,这种情况是合法的;

  1. 既到不了左端点,又到不了右端点;

显然,这种情况是不合法的;

  1. 能到左端点,到不了右端点;

倒序循环,看看当前的右端点是否合法即可;

其实挺简单,但还是没切,赛时切两道题就这么难吗。。。

点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int t;
char c[5000005];
char s[5000005];
int n;
int a;
int mid, r;
int p[5000005];
int vis[5000005];
int main() {
	cin >> t;
	while(t--) {
		mid = 0;
		r = 0;
		scanf("%s", s + 1);
		a = strlen(s + 1);
		if (a == 1) {
			cout << 1 << endl;
			continue;
		}
		n = 1;
		c[1] = '~';
		for (int i = 1; i <= a; i++) {
			c[++n] = s[i];
		}
		c[++n] = '#';
		for (int i = 1; i <= n; i++) {
			p[i] = 0;
			vis[i] = 0;
		}
		for (int i = 2; i <= n - 1; i++) {
			if (i <= r) p[i] = min(r - i + 1, p[2 * mid - i]);
			while(c[i - p[i]] == c[i + p[i]]) p[i]++;
			if (i + p[i] - 1 >= r) {
				r = i + p[i] - 1;
				mid = i;
			}
			if (i + p[i] - 1 >= n - 1) vis[i] = true;
		}
		for (int i = n - 1; i >= 2; i--) {
			if (vis[i]) continue;
			if (i - p[i] + 1 > 2) continue;
			if (vis[i + p[i] - 1]) vis[i] = true;
		}
		for (int i = 2; i <= n - 1; i++) {
			if (vis[i]) {
				cout << i - 1 << ' ';
			}
		}
		cout << endl;
	}
	return 0;
}

排排 100pts

结论题,所以没给大样例。。。

  1. 给出的就是顺序,需要0次操作;

  2. 1或n在自己的位置上,1次;

  3. 有在自己位置上的,且左边没有比它大的,右边没有比它小的,1次;

  4. 1在n上,n在1上,3次;

  5. 剩下情况2次;

对于3,我用了线段树维护,当然也可以用ST表等等;

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
int t;
int n;
int a[500005];
int num[500005];
inline int ls(int x) {
	return x << 1;
}
inline int rs(int x) {
	return x << 1 | 1;
}
struct sss{
	int l, r, ma, mi;
}tr[3000005];
inline void push_up(int id) {
	tr[id].ma = max(tr[ls(id)].ma, tr[rs(id)].ma);
	tr[id].mi = min(tr[ls(id)].mi, tr[rs(id)].mi);
}
void bt(int id, int l, int r) {
	tr[id].l = l;
	tr[id].r = r;
	if (l == r) {
		tr[id].ma = a[l];
		tr[id].mi = a[l];
		return;
	}
	int mid = (l + r) >> 1;
	bt(ls(id), l, mid);
	bt(rs(id), mid + 1, r);
	push_up(id);
}
int ask_ma(int id, int l, int r) {
	if (tr[id].l >= l && tr[id].r <= r) {
		return tr[id].ma;
	}
	int mid = (tr[id].l + tr[id].r) >> 1;
	if (r <= mid) return ask_ma(ls(id), l, r);
	else if (l > mid) return ask_ma(rs(id), l, r);
	else return max(ask_ma(ls(id), l, mid), ask_ma(rs(id), mid + 1, r));
}
int ask_mi(int id, int l, int r) {
	if (tr[id].l >= l && tr[id].r <= r) {
		return tr[id].mi;
	}
	int mid = (tr[id].l + tr[id].r) >> 1;
	if (r <= mid) return ask_mi(ls(id), l, r);
	else if (l > mid) return ask_mi(rs(id), l, r);
	else return min(ask_mi(ls(id), l, mid), ask_mi(rs(id), mid + 1, r));
}
int main() {
	cin >> t;
	while(t--) {
		cin >> n;
		num[0] = 0;
		bool vis = true;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			if (a[i] != i) vis = false;
		}
		bt(1, 1, n);
		if (vis) {
			cout << 0 << endl;
			continue;
		}
		if (a[1] == 1 || a[n] == n) {
			cout << 1 << endl;
			continue;
		}
		for (int i = 1; i <= n; i++) {
			if (a[i] == i) num[++num[0]] = i;
		}
		bool vi = false;
		for (int i = 1; i <= num[0]; i++) {
			if (a[num[i]] > ask_ma(1, 1, num[i] - 1) && a[num[i]] < ask_mi(1, num[i] + 1, n)) {
				cout << 1 << endl;
				vi = true;
				break;
			}
		}
		if (!vi) {
			if (a[1] == n && a[n] == 1) {
				cout << 3 << endl;
			} else {
				cout << 2 << endl;
			}
		}
	}
	return 0;
}

桥桥 13pts

原题:Luogu P5443 [APIO2019] 桥梁

一个套路:操作分块;

对于在一个块内的所有操作,我们给它们一个时间戳,首先按边权从大到小排序,每次使用可撤销并查集维护修改操作。。。

建议去原题解区看看,我讲的我都看不懂。。。

这玩意得卡常,要不过不了。。。

这几天可撤销并查集倒是学明白了,但这个操作分块还是第一次见;

点击查看代码
#include <iostream>
#include <cstdio>
#include <stack>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int n, m, q;
struct sss{
	int f, t, w, id;
	bool operator <(const sss &A) const {
		return w > A.w;
	}
}e[500005];
struct sas{
	int w, id, tim;
	bool operator <(const sas &A) const {
		return w > A.w;
	}
};
int fa[500005], siz[500005];
int ans[500005], vis[500005], mp[500005];
int sq;
vector<sas> def, ask;
stack<pair<int, pair<int, int> > > s;
int find(int x) {
	return (x == fa[x]) ? x : find(fa[x]);
}
void merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x == y) return;
	if (siz[x] > siz[y]) swap(x, y);
	s.push({siz[x], {x, y}});
	siz[y] += siz[x];
	fa[x] = y;
}
void revoke(int la) {
	while(s.size() > la) {
		fa[s.top().second.first] = s.top().second.first;
		siz[s.top().second.second] -= s.top().first;
		s.pop();
	}
}
void solve() {
	sort(e + 1, e + 1 + m);
	sort(ask.begin(), ask.end());
	for (int i = 1; i <= m; i++) {
		mp[e[i].id] = i;
	}
	vector<sas> de;
	de.clear();
	for (auto i : def) {
		vis[i.id] = -1;
		de.push_back(sas{e[mp[i.id]].w, i.id, 0});
	}
	for (auto i : def) de.push_back(i);
	for (int i = 1; i <= n; i++) {
		fa[i] = i;
		siz[i] = 1;
	}
	while(!s.empty()) s.pop();
	int now = 1;
	for (auto i : ask) {
		while(now <= m && e[now].w >= i.w) {
			if (!vis[e[now].id]) merge(e[now].f, e[now].t);
			now++;
		}
		int ls = s.size();
		for (auto a : de) {
			if (a.tim <= i.tim) vis[a.id] = a.w;
		}
		for (auto a : def) {
			if (vis[a.id] >= i.w) merge(e[mp[a.id]].f, e[mp[a.id]].t);
		}
		ans[i.tim] = siz[find(i.id)];
		revoke(ls);
	}
	for (auto i : de) {
		e[mp[i.id]].w = i.w;
		vis[i.id] = 0;
	}
	def.clear();
	ask.clear();
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		cin >> e[i].f >> e[i].t >> e[i].w;
		e[i].id = i;
	}
	cin >> q;
	sq = sqrt(q);
	int ss;
	for (int i = 1; i <= q; i++) {
		sas x;
		cin >> ss >> x.id >> x.w;
		x.tim = i;
		if (ss == 1) {
			def.push_back(x);
		} else {
			ask.push_back(x);
		}
		if (i % sq == 0) solve();
	}
	if (q % sq != 0) solve();
	for (int i = 1; i <= q; i++) {
		if (ans[i]) cout << ans[i] << '\n';
	}
	return 0;
}
posted @ 2024-08-07 17:00  Peppa_Even_Pig  阅读(22)  评论(0编辑  收藏  举报