题意
对字符串 (s) 进行一次操作,使得 (s) 中所有为 ( ext{BA}) 的子串同时变为 ( ext{AB}) 。定义 (mathrm{f}(s)) 表示不断对 (s) 进行上述操作,直到无法再操作为止,最多能对 (s) 进行的操作次数。
给定字符串 (s) ,要求支持区间 ( ext{AB}) 翻转,查询 (mathrm{f}('mathrm{B}'+s+'mathrm{A}')) 。
题解
发现进行这样的操作的本质是对 (s) 排序,最后所有的 ( ext{A}) 都在 ( ext{B}) 的前面。也就是说,只要存在一个 ( ext{B}) 在 ( ext{A}) 前面,那么这个字符串就还能被操作。发现所有 ( ext{B}) 的相对位置是不变的,所以只需要考虑最左边的那个 ( ext{B}) 被移动到正确的位置上的操作次数。
显然,如果每次操作都让最左边的 ( ext{B}) 移动了一位,那么总操作次数即为 (mathrm{cnt}( ext{A})+1) (这里 (mathrm{cnt}) 计算的是 (s) 中字母的个数,不包括两段加入的字符),但是并不是每次操作都会移动最左边的 ( ext{B}) 。不难发现,本次操作不会移动某个位置的 ( ext{B}) ,当且仅当它后面紧跟着一个 ( ext{B}) ,而不是 ( ext{A})(后面没有字符除外),我们将这种情况称作这个 ( ext{B}) 被后面的 ( ext{B}) 阻挡。
考虑下面这种情况(假设最后一段 ( ext{A}) 足够长):
若 (c_1geq c_2) ,那么当最左边的 ( ext{B}) 移动到第一段 ( ext{A}) 之后时,长度为 (c_2) 的那段 ( ext{B}) 已经全部移动,即此时最左边的 ( ext{B}) 后面紧接着的是一个 ( ext{A}) ,那么它就可以继续向后移动,换而言之,这段长度为 (c_2) 的 ( ext{B}) 对最左边的 ( ext{B}) 的移动无影响。
否则 (c_1<c_2) ,最左边的 (B) 移动到 ( ext{A}) 之后时,后面那段 ( ext{B}) 还有 (c_2-c_1) 个没有移动,即它后面紧接着有 (c_2-c_1) 个 ( ext{B}) ,再进行操作时这个 ( ext{B}) 就无法移动了,它再次移动还需要 (c_2-c_1) 次操作。
如果最后一段 ( ext{A}) 不够长,即下面一种情况:
其中 (c_3<c_4) ,那么 (c_2) 这一段就不能顺利地走过 (c_3) 这一段了,它会被后面 (c_4) 这一段阻挡 (c_4-c_3) 次操作,那么最左边的 ( ext{B}) 就会被阻挡 (c_4+c_2-c_1-c_3) 次操作。
到这里就能大概看出结论了:若将 ( ext{A}) 看成 (-1) ,( ext{B}) 看成 (1) ,序列的最大前缀和为 (mathrm{lmax}(s)) ,答案即为 (mathrm{cnt}( ext{A})+1+mathrm{lmax}(s)) 。
用线段树维护即可。
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <climits>
#define Rint register int
#define INF 0x3f3f3f3f
using namespace std;
typedef long long lxl;
const int maxn=2e5+5;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,q;
char s[maxn];
namespace Segment_Tree
{
struct node
{
int l,r,cntA,cntB;
int sum,lmin,lmax;
bool tag;
node(int l,int r,int cntA,int cntB,int sum,int lmin=0,int lmax=0,bool tag=false)
:l(l),r(r),cntA(cntA),cntB(cntB),sum(sum),lmin(lmin),lmax(lmax),tag(tag){}
node(){}
inline node operator + (const node &T)const
{
node res(l,T.r,cntA+T.cntA,cntB+T.cntB,sum+T.sum);
res.lmin=min(lmin,sum+T.lmin);
res.lmax=max(lmax,sum+T.lmax);
return res;
}
}tree[maxn<<2];
#define ls (p<<1)
#define rs (p<<1|1)
inline void reverse(int p)
{
if(!p) return;
swap(tree[p].cntA,tree[p].cntB);
swap(tree[p].lmin,tree[p].lmax);
tree[p].lmin=-tree[p].lmin;
tree[p].lmax=-tree[p].lmax;
tree[p].sum=-tree[p].sum;
tree[p].tag^=1;
}
inline void push_down(int p)
{
if(!tree[p].tag) return;
reverse(ls);
reverse(rs);
tree[p].tag=0;
}
inline void set(int p,char c)
{
tree[p].sum=c=='A'?-1:1;
c=='A'?(tree[p].cntA=1):(tree[p].cntB=1);
tree[p].lmin=min(0,tree[p].sum);
tree[p].lmax=max(0,tree[p].sum);
}
void build(int p,int l,int r)
{
tree[p]=node(l,r,0,0,0);
if(l==r) return set(p,s[l]),void();
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
tree[p]=tree[ls]+tree[rs];
}
void modify(int p,int L,int R)
{
int l=tree[p].l,r=tree[p].r;
if(L<=l&&r<=R) return reverse(p),void();
push_down(p);
int mid=(l+r)>>1;
if(L<=mid) modify(ls,L,R);
if(R>mid) modify(rs,L,R);
tree[p]=tree[ls]+tree[rs];
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("P100137.in","r",stdin);
#endif
read(n);
scanf(" %s
",s+1);
Segment_Tree::build(1,1,n);
read(q);
int l,r;
while(q--)
{
read(l),read(r);++l,++r;
Segment_Tree::modify(1,l,r);
printf("%d
",Segment_Tree::tree[1].cntA+Segment_Tree::tree[1].lmax+1);
}
return 0;
}