链接:点击打开链接
题意:给出长度为n的数组,初始每个点都是1,每次操作可能将某个点取反,或者询问某个点所在的区间中连续1的个数最多是多少
代码:
#include <stack>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int siz=50005;
int lsum[siz<<2],rsum[siz<<2];
void build(int l,int r,int rt){
lsum[rt]=rsum[rt]=r-l+1;
if(l==r)
return;
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
}
void pushup(int rt,int p){
lsum[rt]=lsum[rt<<1];
rsum[rt]=rsum[rt<<1|1];
if(lsum[rt<<1]==p-(p>>1))
lsum[rt]+=lsum[rt<<1|1];
if(rsum[rt<<1|1]==(p>>1))
rsum[rt]+=rsum[rt<<1];
} //区间合并
void Change(int p,int q,int l,int r,int rt){
if(l==r){
lsum[rt]=rsum[rt]=q;
return;
}
int m=(l+r)>>1;
if(p<=m)
Change(p,q,l,m,rt<<1);
if(p>m)
Change(p,q,m+1,r,rt<<1|1);
pushup(rt,r-l+1);
}
int query(int p,int l,int r,int rt){
if(l==r)
return 0;
int m=(l+r)>>1;
if(m-rsum[rt<<1]+1<=p&&p<=m+lsum[rt<<1|1])
return rsum[rt<<1]+lsum[rt<<1|1];
if(p<=m)
return query(p,l,m,rt<<1);
if(p>m)
return query(p,m+1,r,rt<<1|1);
}
int main(){ //lsum表示从左端点开始最长连续长度
char op; //rsum表示从右端点开始最长连续长度
int n,m,u; //主要就是pushup时可能合并,剩下的和单点更新查询类似
while(scanf("%d%d",&n,&m)!=EOF){
build(1,n,1);
stack<int> sta;
while(m--){
cin>>op;
if(op=='D'){
scanf("%d",&u);
sta.push(u);
Change(u,0,1,n,1);
}
else if(op=='R'){
u=sta.top();
sta.pop();
Change(u,1,1,n,1);
}
else{
scanf("%d",&u);
printf("%d\n",query(u,1,n,1));
}
}
}
return 0;
}