题目大意:给一个长度为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;
}