英文题面不放了,直接上翻译:
题目描述
给你n个数,每个数是4或者7,给你m个任务完成
switch l r 把[l,r]位置的4换成7,7换成4
count 计算n个数的最长不下降子序列的长度
N个数的不下降子序列是这n个数移除掉0个或者若干个位置的数,并且满足从第2个数开始每一个数不小于前一个数的大小。
输入格式
第一行n,m
第二行n个数字
接下来m行每行一个命令
输出格式
对于每一个count的命令,输出n个数的最长不下降子序的长度
输入输出样例
看到区间问题,线段树之类的肯定没得跑。
当然将$4,7$转成$0,1$应该都能想到。
不过怎样区间翻转是一个问题。
我们记录最长不上升子序列的长度和最长不下降子序列的长度,然后分别维护即可。
区间翻转的时候翻转一下就好。
那,维护怎么办?
其实最长不下降子序列只有一种情况:前面若干个$4$,后面若干个$7$。
那我们只要搞出分界点就好。
这里的分界点指的是最后一个$4$的位置。
而分界点只会在三个地方:左儿子区间$[l,mid-1]$中,$mid$,右儿子区间$[mid+1,r]$中。
于是分别计算长度,取最大值就好。
最长不上升子序列同理。
复杂度$O(mlog_2n)$。
代码还是挺好码的。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define LSON rt<<1 #define RSON rt<<1|1 #define FOUR(x) a[x].four #define SEVEN(x) a[x].seven #define SIGN(x) a[x].c #define UPON(x) a[x].upon #define DOWN(x) a[x].down #define LSIDE(x) a[x].l #define RSIDE(x) a[x].r #define WIDTH(x) (RSIDE(x)-LSIDE(x)+1) #define MAXN 1000010 using namespace std; int n,m; char ch[MAXN]; struct Segment_Tree{ int seven,four,c,upon,down; int l,r; }a[MAXN<<2]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline void pushup(int rt){ FOUR(rt)=FOUR(LSON)+FOUR(RSON); SEVEN(rt)=SEVEN(LSON)+SEVEN(RSON); UPON(rt)=max(FOUR(LSON)+SEVEN(RSON),max(FOUR(LSON)+UPON(RSON),UPON(LSON)+SEVEN(RSON))); DOWN(rt)=max(SEVEN(LSON)+FOUR(RSON),max(SEVEN(LSON)+DOWN(RSON),DOWN(LSON)+FOUR(RSON))); } inline void pushdown(int rt){ if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return; SIGN(LSON)^=1; swap(FOUR(LSON),SEVEN(LSON)); swap(UPON(LSON),DOWN(LSON)); SIGN(RSON)^=1; swap(FOUR(RSON),SEVEN(RSON)); swap(UPON(RSON),DOWN(RSON)); SIGN(rt)=0; } void buildtree(int l,int r,int rt){ LSIDE(rt)=l;RSIDE(rt)=r;SIGN(rt)=0; if(l==r){ FOUR(rt)=(ch[l]=='4'); SEVEN(rt)=(FOUR(rt)^1); UPON(rt)=DOWN(rt)=1; return; } int mid=l+r>>1; buildtree(l,mid,LSON); buildtree(mid+1,r,RSON); pushup(rt); } void update(int l,int r,int rt){ if(l<=LSIDE(rt)&&RSIDE(rt)<=r){ SIGN(rt)^=1; swap(FOUR(rt),SEVEN(rt)); swap(UPON(rt),DOWN(rt)); return; } pushdown(rt); int mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)update(l,r,LSON); if(mid<r)update(l,r,RSON); pushup(rt); } void work(){ int l,r; while(m--){ scanf("%s",ch); if(ch[0]=='s'){ l=read();r=read(); update(l,r,1); } else printf("%d ",UPON(1)); } } void init(){ n=read();m=read();scanf("%s",ch+1); buildtree(1,n,1); } int main(){ init(); work(); return 0; }