Lucky Queries (线段树的区间合并)

Lucky Queries

 CodeForces - 145E 

  Petya loves lucky numbers very much. Everybody knows that lucky numbers are positive integers whose decimal record contains only the lucky digits 4 and 7. For example, numbers 47, 744, 4 are lucky and 5, 17, 467 are not.

Petya brought home string s with the length of n. The string only consists of lucky digits. The digits are numbered from the left to the right starting with 1. Now Petya should execute m queries of the following form:

  • switch l r — "switch" digits (i.e. replace them with their opposites) at all positions with indexes from l to r, inclusive: each digit 4 is replaced with 7and each digit 7 is replaced with (1 ≤ l ≤ r ≤ n);
  • count — find and print on the screen the length of the longest non-decreasing subsequence of string s.

Subsequence of a string s is a string that can be obtained from s by removing zero or more of its elements. A string is called non-decreasing if each successive digit is not less than the previous one.

Help Petya process the requests.

Input

The first line contains two integers n and m (1 ≤ n ≤ 106, 1 ≤ m ≤ 3·105) — the length of the string s and the number of queries correspondingly. The second line contains n lucky digits without spaces — Petya's initial string. Next m lines contain queries in the form described in the statement.

Output

For each query count print an answer on a single line.

Examples

Input
2 3
47
count
switch 1 2
count
Output
2
1
Input
3 5
747
count
switch 1 1
count
switch 1 3
count
Output
2
3
2

Note

In the first sample the chronology of string s after some operations are fulfilled is as follows (the sought maximum subsequence is marked with bold):

  1. 47
  2. 74
  3. 74

In the second sample:

  1. 747
  2. 447
  3. 447
  4. 774
  5. 774

题意:n代表字符串的长度,m代表操作的次数。两种操作:count:输出该字符串中非递减子序列的最大长度(子序列不是子串,不需要连续)switch:表示将从l 到 r的所有字符改变,4变成7,7变成4

题解:

在线段树中维护一下值:

len4表示全是4的最长子序列。

len7表示全是7的最长子序列。

len47表示以4开头以7结尾的最长子序列。

对于操作2,因为反转之后对len4,len7,len47的值影响较大(主要还是len47),所以一般对这样的题都是直接维护两个值,一个是当前的,一个是反转后的,当进行反转操作时再交换就好了。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int maxn=1e6+10;
  7 int n,m; 
  8     char s[maxn];
  9     char op[20];
 10 struct node{
 11     int l;
 12     int r;
 13     int laz;
 14     int len4[2],len7[2],len47[2];
 15 }e[maxn<<2];
 16 void pushup(int cur,int c)
 17 {
 18     e[cur].len4[c]=e[cur<<1].len4[c]+e[cur<<1|1].len4[c];//4的长度为左子树4的长度+右子树4的长度 
 19     e[cur].len7[c]=e[cur<<1].len7[c]+e[cur<<1|1].len7[c];
 20     int temp=e[cur<<1].len4[c]+max(e[cur<<1|1].len7[c],e[cur<<1|1].len47[c]);//len47=左子树len4+右子树len47 左子树len4+右子树len7  左子树len47+右子树len7中取较大的 
 21     e[cur].len47[c]=max(temp,e[cur<<1].len47[c]+e[cur<<1|1].len7[c]);
 22     return;
 23 }
 24 void change(int cur)
 25 {
 26     e[cur].laz^=1;
 27     swap(e[cur].len4[0],e[cur].len4[1]);
 28     swap(e[cur].len7[0],e[cur].len7[1]);
 29     swap(e[cur].len47[0],e[cur].len47[1]);
 30 return;
 31 }
 32 void pushdown(int cur)
 33 {
 34     if(e[cur].laz)
 35     {
 36         //int mid=(e[cur].l+e[cur].r)/2;
 37         change(cur<<1);
 38         change(cur<<1|1);
 39         e[cur].laz=0;
 40     }
 41     return;
 42 }
 43 void build(int l,int r,int cur)
 44 {
 45     e[cur].l=l;
 46     e[cur].r=r;
 47     e[cur].laz=0;
 48     if(l==r)
 49     {
 50         if(s[l]=='4')
 51         {
 52             e[cur].len4[0]=e[cur].len7[1]=1;//e[cur].len4[0]代表没改变前len4为1,e[cur].len7[1]=1表示如果把4的值改变为7,那么len7为1 len数组中0代表没改变,1代表改变后的值 
 53             e[cur].len4[1]=e[cur].len7[0]=0; 
 54         }
 55         else
 56         {
 57             e[cur].len7[0]=e[cur].len4[1]=1;
 58             e[cur].len7[1]=e[cur].len4[0]=0;
 59         }
 60         e[cur].len47[0]=e[cur].len47[1]=0;
 61         return;
 62     }
 63     int mid=(l+r)/2;
 64     build(l,mid,cur<<1);
 65     build(mid+1,r,cur<<1|1);
 66     pushup(cur,0);
 67     pushup(cur,1);
 68 }
 69 void update(int pl,int pr,int cur)
 70 {
 71     if(pl<=e[cur].l&&e[cur].r<=pr)
 72     {
 73         change(cur);
 74         return;
 75     }
 76     pushdown(cur);
 77     int mid=(e[cur].l+e[cur].r)/2;
 78     if(pl<=mid)
 79         update(pl,pr,cur<<1);
 80     if(pr>mid)
 81         update(pl,pr,cur<<1|1);
 82     pushup(cur,0);
 83     pushup(cur,1);
 84 }
 85 int main()
 86 {
 87     scanf("%d%d",&n,&m);
 88     scanf("%s",s+1);
 89     build(1,n,1);
 90     while(m--)
 91     {
 92         int x,y;
 93         scanf("%s",op);
 94         if(op[0]=='s')
 95         {
 96             scanf("%d%d",&x,&y);
 97             update(x,y,1);
 98         }
 99         else
100         {
101             printf("%d\n",max(e[1].len4[0],max(e[1].len47[0],e[1].len7[0])));
102         }
103     }
104 }

 

转载于:https://www.cnblogs.com/1013star/p/9600810.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值