题目大意:给一个长度为n的47序列(就是只有4和7),两种操作:
操作1:count 要求输出当前数列的最长非下降子序列(注意是子序列,不是子串。。。一开始没看清题WA半天)。
操作2 : switch l r 将区间[l,r]之间的数反转(这里的反转指的是4变成7 7变成4)
然后就是给你一堆操作,对每一个操作1输出相应的值。。。
PS:这竟然是div1 的 E,我觉得就是一道很中规中矩的线段树啊。。。
思路:在线段树中维护一下值:
len4表示全是4的最长子序列。
len7表示全是7的最长子序列。
len47表示以4开头以7结尾的最长子序列。
rev当然是懒惰标记啦。。。
对于操作2,因为反转之后对len4,len7,len47的值影响较大(主要还是len47),所以我一般对这样的题都是直接维护两个值,一个是当前的,一个是反转后的,当进行反转操作时再交换就好了。
对于两个区间合并 len4和len7很好更新,这里就不讲了,主要还是len47(其实也很简单的。。。),len47就三种情况,1,左边的len4+右边的len47。2,左边的len4+右边的len7。3左边的len47+右边的len7。三种情况取个大的就行了。还有。。。没什么要注意了吧。。两个操作都是很普通的线段树操作,没什么可讲的了,代码实现如下。
#include <iostream> #include <string.h> #include <stdio.h> #include <algorithm> #define maxn 1000100 #define mid ((t[p].l+t[p].r)>>1) #define ls (p<<1) #define rs (ls|1) using namespace std; struct tree { int l,r; int len4[2],len7[2],len47[2]; int rev; }t[maxn<<2]; int a[maxn]; int max(int a,int b) { return a>b?a:b; } void pushup(int p,int c) { t[p].len4[c]=t[ls].len4[c]+t[rs].len4[c]; t[p].len7[c]=t[ls].len7[c]+t[rs].len7[c]; int tmp=t[ls].len4[c]+max(t[rs].len7[c],t[rs].len47[c]); t[p].len47[c]=max(tmp,t[ls].len47[c]+t[rs].len7[c]); } void change(int p) { t[p].rev^=1; swap(t[p].len4[0],t[p].len4[1]); swap(t[p].len7[0],t[p].len7[1]); swap(t[p].len47[0],t[p].len47[1]); } void pushdown(int p) { if(t[p].rev) { change(ls); change(rs); t[p].rev=0; } } void build(int p,int l,int r) { t[p].l=l,t[p].r=r,t[p].rev=0; if(l==r) { if(a[l]) { t[p].len7[0]=t[p].len4[1]=1; t[p].len7[1]=t[p].len4[0]=0; } else { t[p].len7[0]=t[p].len4[1]=0; t[p].len7[1]=t[p].len4[0]=1; } t[p].len47[0]=t[p].len47[1]=0; return; } build(ls,l,mid); build(rs,mid+1,r); pushup(p,0); pushup(p,1); } int get(int p,int x) { if(t[p].l==t[p].r) { if(t[p].len4[0]) return 0; return 1; } pushdown(p); if(x>mid) return get(rs,x); return get(ls,x); } void reverse(int p,int l,int r) { if(t[p].l==l&&t[p].r==r) { change(p); return; } pushdown(p); if(l>mid) reverse(rs,l,r); else if(r<=mid) reverse(ls,l,r); else { reverse(ls,l,mid); reverse(rs,mid+1,r); } pushup(p,0); pushup(p,1); } char str[maxn],tmp[10]; int main() { int n,m,i; scanf("%d%d",&n,&m); scanf("%s",str+1); for(i=1;i<=n;i++) { if(str[i]=='4') a[i]=0; else a[i]=1; } build(1,1,n); while(m--) { int l,r; scanf("%s",tmp); if(tmp[0]=='s') { scanf("%d%d",&l,&r); reverse(1,l,r); } else { printf("%d\n",max(t[1].len4[0],max(t[1].len7[0],t[1].len47[0]))); } } return 0; }