题目描述:N个数,有0/1两种状态,Q个操作:(1)置反单点状态;(2)查询最长交错序列长度(相邻的状态不同)
N<=200,000,Q<=200,000
解析:一开始把偶数位取反,这样就变成了维护一条最长的连续序列。每个节点维护它的前缀和后缀和和最长连续序列长度。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct point
{
int val;
int h;
int q;
}s[800010];
int n,q,x;
int a[200010];
void build(int node,int l,int r)
{
s[node].h=s[node].q=s[node].val=1;
if(l==r)
return;
int mid=(l+r)/2;
build(node*2,l,mid);
build(node*2+1,mid+1,r);
}
void change(int node,int l,int r,int x)
{
if(l==r)
{
a[l]=1-a[l];
return;
}
int mid=(l+r)/2;
if(x<=mid)
change(node*2,l,mid,x);
else
change(node*2+1,mid+1,r,x);
int ans1=0;
s[node].q=s[node*2].q;
s[node].h=s[node*2+1].h;
if(a[mid]==a[mid+1])
{
ans1=s[node*2].h+s[node*2+1].q;
if(mid-l+1==s[node*2].q)
s[node].q=max(s[node].q,s[node*2].q+s[node*2+1].q);
if(r-mid==s[node*2+1].h)
s[node].h=max(s[node].h,s[node*2+1].h+s[node*2].h);
}
int ans2=max(s[node*2].val,s[node*2+1].val);
s[node].val=max(ans1,ans2);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
if(i%2==0)
a[i]=1;
build(1,1,n);
for(int i=1;i<=q;i++)
{
scanf("%d",&x);
change(1,1,n,x);
printf("%d\n",s[1].val);
}
return 0;
}