Description
You are given a string S no longer than 100,000 consisting of characters 0-9 only. And two kinds of operations will be performed on S:
Flip i j: for each i <= k <= j, Sk is replaced substituted with 9 - Sk.
Query: you are to calculate the length of the longest non-decreasing substring of S.
Input
The first line of the input contains a single integer t, the number of test cases.
For each test case, the first line contains two integers, n and m(1 <= m <= 5000), indicating the length of S and the number of operations to perform.
Then m lines follow. Each line gives a single operation that is either “flip i j”(1 <= i <= j <= n) or “query”.
There is a blank line after each test case.
Output
For each query operation, print the length of the longest non-decreasing substring of S on a single line.
Print a blank line after each test case.
Sample Input
Sample Output
题意:flip操作是把区间内每个数用9减,询问操作是询问目前最长的不减序列有多长。
这道题折腾了我几天。。。一直WA,还想不明白为什么WA。。折腾到今天终于过了,看来是我线段树太水了,很多细节没理解到位。。这道题挺好的。
区间合并线段树一般需要维护很多东西,从左开始,从右开始,整个区间。。
这道题要维护从左开始不减最长,从右开始不减最长,整个区间不减最长,左边第一个数字,右边第一个数字。。又因为有旋转操作,旋转的话不减就变成了不增。所以还要维护从左开始不增最长,从右开始不增最长,整个区间不增最长。。
用一个rot数组代表该区间旋转了几次。在更新的过程中如果该节点旋转次数是奇数次,就pushdown。也就是把一整个区间分成几个不重合区间的思想,这样就不用查询到底。
一开始我把旋转函数写在了maintain函数里面,每次maintain的时候判断这个区间的rot,如果是奇数就旋转。但是WA,终于知道为什么了,如果一个区间第一次rot+1,然后旋转了,如果又旋转这个区间,rot+1变成偶数,没旋转。实际上这个区间没旋转,而我这个却旋转了一次。。。也就是判断rot奇偶的时候必须这个区间以前没有旋转过。。
后来我把旋转函数没放在maintain里面,maintain函数的功能就是不包括根节点只包括子节点的旋转操作,结果我又在pushdown的时候maintain了子节点。。(如果把旋转推到子节点,maintain子节点以后子节点又变成了旋转之前的。。),所以只有在把这个点的rot都推下去以后才能maintain这个点。
区间合并的maintain函数都很恶心的。。。要仔细写。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define INF 0x3f3f3f3f
#define MAXN 100010
#define MAXNODE 4*MAXN
using namespace std;
int T,N,M,rot[MAXNODE],li[MAXNODE],ld[MAXNODE],ri[MAXNODE],rd[MAXNODE],si[MAXNODE],sd[MAXNODE],lz[MAXNODE],rz[MAXNODE];
char a[MAXN];
void rotate(int o){
rot[o]++;
swap(si[o],sd[o]);
swap(li[o],ld[o]);
swap(ri[o],rd[o]);
lz[o]=9-lz[o];
rz[o]=9-rz[o];
}
void maintain(int o,int L,int R){
if(L<R){
int lc=(o<<1),rc=(o<<1|1),mid=(L+R)>>1;
si[o]=max(si[lc],si[rc]);
sd[o]=max(sd[lc],sd[rc]);
li[o]=li[lc];
ld[o]=ld[lc];
ri[o]=ri[rc];
rd[o]=rd[rc];
lz[o]=lz[lc];
rz[o]=rz[rc];
if(lz[rc]>=rz[lc]){
si[o]=max(si[o],ri[lc]+li[rc]);
if(li[lc]==mid-L+1) li[o]+=li[rc];
if(ri[rc]==R-mid) ri[o]+=ri[lc];
}
if(lz[rc]<=rz[lc]){
sd[o]=max(sd[o],rd[lc]+ld[rc]);
if(ld[lc]==mid-L+1) ld[o]+=ld[rc];
if(rd[rc]==R-mid) rd[o]+=rd[lc];
}
}
}
void pushdown(int o){
rotate(o<<1);
rotate(o<<1|1);
rot[o]=0;
}
void update(int o,int L,int R,int ql,int qr){
if(ql<=L&&qr>=R){
rotate(o);
return;
}
else{
if(rot[o]%2) pushdown(o);
int lc=(o<<1),rc=(o<<1|1),mid=(L+R)>>1;
if(ql<=mid) update(lc,L,mid,ql,qr);
if(qr>mid) update(rc,mid+1,R,ql,qr);
}
maintain(o,L,R);
}
void build(int o,int L,int R){
rot[o]=0;
if(L==R){
li[o]=ld[o]=ri[o]=rd[o]=si[o]=sd[o]=1;
lz[o]=rz[o]=a[L]-'0';
return;
}
else{
int mid=(L+R)>>1;
build(o<<1,L,mid);
build(o<<1|1,mid+1,R);
}
maintain(o,L,R);
}
int main(){
freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d%d",&N,&M);
scanf("%s",a+1);
build(1,1,N);
while(M--){
int ql,qr;
char str[10];
scanf("%s",str);
if(str[0]=='f'){
scanf("%d%d",&ql,&qr);
update(1,1,N,ql,qr);
}
else printf("%d\n",si[1]);
}
puts("");
}
return 0;
}