题意:
给你一数组,数组的值只有0(A糖果)和1(B糖果)两种,对这个数组有两种操作:(1)把区间L到R的值更改为v, (2)询问从区间L到R最多有多少个1是连续的。
线段树维护三个值 pre,sub,suf 分别代表前缀,子串,后缀连续为1的个数,
三个值的更新方式为下图,很好理解
void pushup(Node &rt,Node a,Node b,int l,int r){
int mid=(l+r)/2;
if(a.pre==mid-l+1){
rt.pre=a.pre+b.pre;
}else rt.pre=a.pre;
if(b.suf==r-mid){
rt.suf=b.suf+a.suf;
}else rt.suf=b.suf;
rt.sub=max(a.suf+b.pre,max(a.sub,b.sub));
}
lazy的标记在build的时候初始化,向下更新的时候,左右孩子的三个值也要维护,当前节点设置标记时,也要维护这三个值。
query的时候,根据查询范围,来分类,R<=mid 说明要在左子树查询,L>=mid+1,在右子树,其他的就是mid在L和R的中间。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
typedef long long ll;
const ll INF=1e15+10;
const int maxn=1e6+5;
char s[1000006];
int cnt;
struct Node{
int pre,suf,sub,lazy;
}node[maxn*4];
void pushup(Node &rt,Node a,Node b,int l,int r){
int mid=(l+r)/2;
if(a.pre==mid-l+1){
rt.pre=a.pre+b.pre;
}else rt.pre=a.pre;
if(b.suf==r-mid){
rt.suf=b.suf+a.suf;
}else rt.suf=b.suf;
rt.sub=max(a.suf+b.pre,max(a.sub,b.sub));
}
void pushdown(Node &rt,Node &a,Node &b,int l,int r){
if(rt.lazy!=-1){
a.lazy=b.lazy=rt.lazy;
if(rt.lazy==0)
a.pre=a.sub=a.suf=b.pre=b.sub=b.suf=0;
else{
int mid=(l+r)/2;
a.pre=a.sub=a.suf=mid-l+1;
b.pre=b.sub=b.suf=r-mid;
}
rt.lazy=-1;
}
}
void build(int l,int r,int rt){
node[rt].lazy=-1;
if(l==r){
Node &t=node[rt];
if(s[cnt++]-'A'==1)
t.sub=t.pre=t.suf=1;
else t.sub=t.pre=t.suf=0;
return;
}
int mid=(l+r)/2;
build(l,mid,rt*2);
build(mid+1,r,rt*2+1);
pushup(node[rt],node[rt*2],node[rt*2+1],l,r);
}
void update(int L,int R,int k,int l,int r,int rt){
if(L<=l&&r<=R){
node[rt].lazy=k;
if(k==0)
node[rt].sub=node[rt].suf=node[rt].pre=0;
else node[rt].sub=node[rt].suf=node[rt].pre=r-l+1;
return;
}
int mid=(l+r)/2;
pushdown(node[rt],node[rt*2],node[rt*2+1],l,r);
if(L<=mid) update(L,R,k,l,mid,rt*2);
if(R>=mid+1) update(L,R,k,mid+1,r,rt*2+1);
pushup(node[rt],node[rt*2],node[rt*2+1],l,r);
}
Node query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return node[rt];
}
pushdown(node[rt],node[rt*2],node[rt*2+1],l,r);
int mid=(l+r)/2;
Node ans;
if(R<=mid) return query(L,R,l,mid,rt*2);
else if(L>=mid+1) return query(L,R,mid+1,r,rt*2+1);
else pushup(ans,query(L,R,l,mid,rt*2),query(L,R,mid+1,r,rt*2+1),l,r);
return ans;
}
int main(){
//freopen("out.txt","w",stdout);
int T,cas=1;
scanf("%d",&T);
while(T--){
printf("Case #%d:\n",cas++);
int n,m;
cnt=0;
scanf("%d %d",&n,&m);
scanf("%s",s);
build(1,n,1);
while(m--){
int op,l,r,k;
scanf("%d",&op);
if(op==1){
scanf("%d %d %d",&l,&r,&k);
k--;
update(l,r,k,1,n,1);
}else{
scanf("%d %d",&l,&r);
Node ans=query(l,r,1,n,1);
printf("%d\n",ans.sub);
}
}
}
return 0;
}