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();
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址