Japan Alumni Group Summer Camp 2018 Day 2J AB Sort JZOJ 100137. 胖头鱼的排序(推性质+线段树)

https://gmoj.net/senior/#main/show/100137

题解:

对于一个串\(S\),怎么求\(f(S)\)

把S结尾的一段连续B去掉。

我们知道最后一定是变成AAA……BBB……

考虑将'A'看做+1,’B‘看做-1,变成了一个折线图

每次会使最低点+1,直到最低点=A的个数,那么答案显然是A的个数-最小前缀和。

这题要求的是\(f('B'+S+'A')\),这样结尾就不用去B了,\(f=S中'A'的个数-S的最小前缀和+1\)

每次由区间A变B、B变A操作,线段树维护即可。

我一开始以为是区间reverse操作,所以写了平衡树。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 2e5 + 5;

int n; char str[N];

void Init() {
	scanf("%d", &n);
	scanf("%s", str + 2);
}


#define x0 t[x][0]
#define x1 t[x][1]
int rt, fa[N], t[N][2], siz[N], rev[N], dd[N];
int z[N], s[N], f[N], g[N], c1[N], c2[N];

void upd(int x) {
	if(x) {
		siz[x] = siz[x0] + siz[x1] + 1;
		c1[x] = c1[x0] + c1[x1] + (z[x] == 1);
		c2[x] = c2[x0] + c2[x1] + (z[x] == -1);
		s[x] = s[x0] + s[x1] + z[x];
		f[x] = min(f[x0], s[x0] + z[x] + f[x1]);
		g[x] = min(g[x0], -s[x0] - z[x] + g[x1]);
	}
}
void fan(int x) { if(x) z[x] = -z[x], s[x] = -s[x], swap(f[x], g[x]), swap(c1[x], c2[x]), rev[x] ^= 1;}
void down(int x) { if(rev[x]) fan(x0), fan(x1), rev[x] = 0;}
int lr(int x) { return t[fa[x]][1] == x;}
void ro(int x) {
	int y = fa[x], k = lr(x);
	t[y][k] = t[x][!k]; if(t[x][!k]) fa[t[x][!k]] = y;
	fa[x] = fa[y]; if(fa[y]) t[fa[y]][lr(y)] = x;
	fa[y] = x; t[x][!k] = y;
	upd(y); upd(x);
}
void xc(int x) {
	for(; x; x = fa[x]) dd[++ dd[0]] = x;
	while(dd[0]) down(dd[dd[0] --]);
}
void sp(int x, int y) {
	xc(x);
	for(; fa[x] != y; ro(x)) if(fa[fa[x]] != y)
		ro(lr(x) == lr(fa[x]) ? fa[x] : x);
}
int kth(int x, int k) {
	down(x);
	if(siz[x0] >= k) return kth(x0, k);
	if(siz[x0] + 1 == k) return x;
	return kth(x1, k - siz[x0] - 1);
}

void build() {
	fo(i, 1, n + 2)	{
		if(i == 1 || i == n + 2) z[i] = 0; else
			z[i] = (str[i] == 'B' ? -1 : 1);
		if(i > 1) fa[i] = i - 1, t[i - 1][1] = i;
	}
	sp(n + 2, 0); rt = n + 2;
}

int Q, x, y;

void Work() {
	scanf("%d", &Q);
	fo(ii, 1, Q) {
		scanf("%d %d", &x, &y);
		x += 2, y += 2;
		int p = kth(rt, x - 1);
		int q = kth(rt, y + 1);
		sp(p, 0); sp(q, p);
		int u = t[q][0];
		fan(u);
		sp(u, 0); rt = u;
		pp("%d\n", c1[u] - f[u] + 1);
	}
}

int main() {
	Init();
	build();
	Work();
}
posted @ 2020-02-25 17:04  Cold_Chair  阅读(281)  评论(0编辑  收藏  举报