[BalkanOI2018] Election

题目描述

有一个长度为 $N$ 的字符串 $S[1\dots N]$ ,它仅由 CT 两种字母组成。
现在有 $Q$ 个查询,每个查询包含两个整数 $L$ $R$ ,表示:设新字符串 $S'=S[L\dots R]$ ,至少在 $S'$ 中要删除多少个字符,才能保证:对于 $S'$ 的每一个前缀和后缀,其 C 的数量都不小于 T 的数量。

$N\leq5\times10^5$

题解

线段树维护最大子段和。

代码

const int N = 1e6 + 5;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

namespace Main {
	int n, m;
	int sum[N];
	char s[N];
	struct SegmentTree {
		struct tree {
			int l, r, lmx, rmx, sum, ans;
		}t[N << 2];
#define lson (p << 1)
#define rson (p << 1 | 1)
		tree friend operator + (tree a, tree b) {
			return (tree){a.l, b.r,
			max({0, a.lmx, a.sum + b.lmx}),
			max({0, b.rmx, b.sum + a.rmx}),
			a.sum + b.sum,
			max({a.ans + b.sum, a.sum + b.ans, a.lmx + b.rmx})};
		}
//		void pushup (int p) {
//			t[p].lmx = max({0, t[lson].lmx, t[lson].sum + t[rson].lmx});
//			t[p].rmx = max({0, t[rson].rmx, t[rson].sum + t[lson].rmx});
//			t[p].sum = t[lson].sum + t[rson].sum;
//			t[p].ans = max({t[lson].ans + t[rson].sum, t[lson].sum + t[rson].ans, t[lson].lmx + t[rson].rmx});
//		}
		void build (int p, int l, int r) {
			t[p].l = l, t[p].r = r;
			if (t[p].l == t[p].r) { 
				t[p].lmx = s[l] == 'T';
				t[p].rmx = s[l] == 'T';
				t[p].sum = (s[l] == 'T'? 1: -1);
				t[p].ans = s[l] == 'T';
				return;
			}
			int mid = (t[p].l + t[p].r) >> 1;
			build (lson, l, mid);
			build (rson, mid + 1, r);
			t[p] = t[lson] + t[rson];
		}
		tree query (int p, int l, int r) {
			if (l <= t[p].l && t[p].r <= r) return t[p];
			int mid = (t[p].l + t[p].r) >> 1;
			if (l <= mid && r > mid) return query (lson, l, r) + query (rson, l, r);
			if (l <= mid) return query (lson, l, r);
			else return query (rson, l, r);
		}
	} sgt;
	int main () {
		n = Read();
		scanf ("%s", s + 1);
		for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + (s[i] == 'C');
		sgt.build(1, 1, n);
		int ans = 0;
		for (m = Read(); m--; ) {
			int l = Read(), r = Read();
			//ans ^= sgt.query (1, l, r).ans + (sum[r] - sum[l - 1] == 0);
			printf ("%d\n", sgt.query(1, l, r).ans);
		}
		return 0;
	}
}

int main () {
	string str = "";
//	freopen((str + ".in").c_str(), "r", stdin);
//	freopen((str + ".out").c_str(), "w", stdout);
	Main::main();
	return 0;
}
EOF

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。

博客信息

作者
Jayun
时间
2024-02-21 15:04:24