有一个长度为n的序列,刚开始全是L,给出te个操作,每次操作给出一个x,表示把x从L改为R(R改为L)。每次操作后询问最长的字串,这个字串需要满足相邻位置符号不同。
刚开始我是这么想的:把序列分块成一片片满足的区域,比如LRRLRRRLRLRL被分为|LR|RLR|R|RLRLRL|。然后记录father[i]和r[i]表示i所在区域最左边的编号和i能够向右推的个数,用线段树维护这些区域(加加减减,改来改去),这种做法常数显然很大,还容易写错,可想而知我华丽丽的炸了(WA+TLE)。
后来,Lynstery飘过来说:“这种垃圾题”,然后告诉了我强的不行的做法:序列相邻两个之间如果是相同的,就记为0,否则记为1,举个例子:
L R R L R R R L R L R L
1 0 1 1 0 0 1 1 1 1 1
那么求最长子串就转化为求最长连续1的个数。
接下来还是用线段树处理,每个节点记录MAX,pre,suf表示最长子串,最长前缀和最长后缀,由于每次只是单点修改,所以维护这三个信息是比较简单的:
pre=左儿子pre
if (左儿子MAX=左儿子区间跨度) pre=左儿子MAX+右儿子pre
//左儿子MAX=左儿子区间跨度其实等价于左儿子能够全选
suf=右儿子suf
if (右儿子MAX=右儿子区间跨度) suf=右儿子MAX+左儿子suf
MAX=max(左儿子MAX,右儿子MAX,pre,suf,左儿子suf+右儿子pre)
那么最大值就是MAX[1]。
#include
#include
using namespace std;
const int maxn=200000,maxt=4*maxn,MAXINT=((1<<30)-1)*2+1;
int n,te;
bool vis[maxn+5];
struct SegmentTree
{
int l[maxt+5],r[maxt+5],MAX[maxt+5],pre[maxt+5],suf[maxt+5];
void Build(int L,int R,int p=1)
{
l[p]=L;r[p]=R;MAX[p]=pre[p]=suf[p]=0;
if (L==R) return;int mid=L+(R-L>>1);
Build(L,mid,p<<1);Build(mid+1,R,p<<1|1);
}
void Pushup(int p)
{
pre[p]=pre[p<<1];
if (MAX[p<<1]==r[p<<1]-l[p<<1]+1) pre[p]=MAX[p<<1]+pre[p<<1|1];
suf[p]=suf[p<<1|1];
if (MAX[p<<1|1]==r[p<<1|1]-l[p<<1|1]+1) suf[p]=suf[p<<1]+MAX[p<<1|1];
MAX[p]=max(max(pre[p],suf[p]),max(MAX[p<<1],MAX[p<<1|1]));
MAX[p]=max(MAX[p],suf[p<<1]+pre[p<<1|1]);
}
void Update(int pos,int k,int p=1)
{
if (pospos) return;
if (l[p]==r[p]) {MAX[p]=pre[p]=suf[p]=k;return;}
Update(pos,k,p<<1);Update(pos,k,p<<1|1);
Pushup(p);
}
};
SegmentTree tr;
bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst='+';
while ('9''0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
x=tot*f;
return Eoln(ch);
}
int main()
{
freopen("step.in","r",stdin);
freopen("step.out","w",stdout);
readi(n);readi(te);tr.Build(1,n-1);
while (te--)
{
int x;readi(x);
if (x>1) tr.Update(x-1,vis[x-1]^=1);
if (xtr.Update(x,vis[x]^=1);
printf("%d\n",tr.MAX[1]+1);
}
return 0;
}