[ SCOI 2015 ] 小凸解密码

题目

Luogu
LOJ
Acwing

思路

[ SCOI 2015 ] 小凸解密码
[ SCOI 2015 ] 小凸解密码
[ SCOI 2015 ] 小凸解密码

代码

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200010;
int n, m, A[N], B[N];
char C[N];
struct NODE { int l, r, a, b, s, c; } tr[N << 2];
inline void init(int u, int c) {
	if (c == 0) tr[u].a = tr[u].b = tr[u].c = tr[u].s = 0;
	else tr[u].a = tr[u].b = tr[u].c = 1, tr[u].s = 0;
}
inline NODE operator+(const NODE &l, const NODE &r) { // 运算符重载
	NODE u = (NODE) { l.l, r.r };
	u.c = l.c + r.c, u.s = l.s + r.s;
	u.a = l.a, u.b = r.b;
	if (l.c && r.c && (!l.b || !r.a)) u.s++;
	return u;
}
void build(int u, int l, int r) {
	tr[u].l = l, tr[u].r = r;
	if (l == r) return init(u, B[l]), void(0);
	int mid = (l + r) >> 1;
	build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
	tr[u] = tr[u << 1] + tr[u << 1 | 1];
}
void modify(int u, int x, int c) {
	if (tr[u].l == tr[u].r) return init(u, c), void(0);
	int mid = (tr[u].l + tr[u].r) >> 1;
	if (x <= mid) modify(u << 1, x, c);
	else modify(u << 1 | 1, x, c);
	tr[u] = tr[u << 1] + tr[u << 1 | 1];
}
NODE query(int u, int l, int r) {
	if (l <= tr[u].l && tr[u].r <= r) return tr[u];
	int md = (tr[u].l + tr[u].r) >> 1;
	if (r <= md) return query(u << 1, l, r);
	else if (l > md) return query(u << 1 | 1, l, r);
	else return query(u << 1, l, r) + query(u << 1 | 1, l, r); // 注意讨论
}
int calc(int x) { return ((C[x] == '+') ? (A[x] + A[x - 1]) : (A[x] * A[x - 1])) % 10; }
inline void modify(int pos, int num, char opt) {
	A[pos] = A[pos + n] = num, C[pos] = C[pos + n] = opt;
	if (pos > 1) modify(1, pos, calc(pos)); // 如果是开头, 不用计算
	modify(1, pos + n, calc(pos + n));
	modify(1, pos + 1, calc(pos + 1));
	if (pos < n) modify(1, pos + n + 1, calc(pos + n + 1)); // n + pos + 1 超出长度, 不用算
}
bool check(int mid, int pos) { return query(1, pos + mid, n + pos - mid).s; }
inline int query(int pos) {
    // 这两行注释了也能过, 样例都过不了......
	if (A[pos] == 0 && query(1, pos + 1, pos + n - 1).s == 0) return 0; // 特判 0
	if (query(1, pos, pos + n).s == 0) return -1; // 特判 -1
	modify(1, pos, A[pos]), modify(1, pos + n, A[pos]);
	int l = 0, r = n >> 1;
	while (l < r) {
		int mid = (l + r + 1) >> 1;
		if (query(1, pos + mid, n + pos - mid).s) l = mid;
		else r = mid - 1;
	}
	if (pos > 1) modify(1, pos, calc(pos));
	modify(1, pos + n, calc(pos + n));
	return l + 1; // 注意加 1
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) cin >> A[i] >> C[i];
	for (int i = 1; i <= n; i++) A[i + n] = A[i], C[i + n] = C[i];
	for (int i = 2; i <= n << 1; i++) B[i] = calc(i);
	build(1, 1, n << 1);
	char opt;
	for (int op, pos, num; m-- && cin >> op >> pos; ) // 由于从 1 开始, 下标需要加 1 
		if (op == 2) cout << query(pos + 1) << endl;
		else cin >> num >> opt, modify(pos + 1, num, opt);
	return 0;
}
上一篇:2015年蓝桥杯A组C/C++ 第三题奇妙的数字


下一篇:大牛证券乐视网上市前三年就开始造假