线段树练习 区间合并
题目链接http://www.codeforces.com/problemset/problem/145/E
蛮好的题目
一连串由4、7组成的字符串
两种操作:count 输出整个区间内最长的不下降子序列的长度
switch a b 将a、b之间的数4变成7 7变成4
注意,最长不下贱子序列不一定要连续
一般情况下,不连续的最长不下降子序列的长度是无法维护的,但是这道题目的特殊性显而易见,只有4 7 两种数字,相当于0 1
做法:
1:分别记录区间最长不下降和最长不上升的序列的长度,这样子进行异或操作的时候可以直接互换
2:记录区间0的个数和1的个数,利用这两个信息可以 在将信息往上传的时候 维护区间最长的不下降和不上升序列的长度,这里仔细想想
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1000010;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
char str[maxn];
struct node{
int col;
int n0,n1,sum,ld;
void make(){
col^=1;
n0^=n1;n1=n0^n1;n0^=n1;
sum^=ld;ld=sum^ld;sum^=ld;
}
void init(){
col=n0=n1=sum=ld=0;
}
}a[maxn<<2];
int max(int a,int b){
return a>b?a:b;
}
void pushdown(int rt){
if(a[rt].col){
a[rt].col=0;
a[rt<<1].make();
a[rt<<1|1].make();
}
}
void pushup(int rt){
a[rt].n0=a[rt<<1].n0+a[rt<<1|1].n0;
a[rt].n1=a[rt<<1].n1+a[rt<<1|1].n1;
a[rt].sum=max(a[rt<<1].sum+a[rt<<1|1].n1,a[rt<<1|1].sum+a[rt<<1].n0);
a[rt].ld=max(a[rt<<1].ld+a[rt<<1|1].n0,a[rt<<1|1].ld+a[rt<<1].n1);
}
void update(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
a[rt].make();
return ;
}
pushdown(rt);
int m=(l+r)>>1;
if(L<=m) update(L,R,lson);
if(R>m) update(L,R,rson);
pushup(rt);
}
void build(int l,int r,int rt){
a[rt].init();
if(l==r){
a[rt].n1=(str[l]=='7');
a[rt].n0=!a[rt].n1;
a[rt].ld=a[rt].sum=1;
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
int main(){
int n,m,l,r;
char op[10];
scanf("%d%d",&n,&m);
scanf("%s",str+1);
build(1,n,1);
while(m--){
scanf("%s",op);
if(op[0]=='s') {
scanf("%d%d",&l,&r);
update(l,r,1,n,1);
}
else printf("%d\n",a[1].sum);
}
}