Codeforces 145E. Lucky Queries 线段树

题目链接;

题目描述:

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 7 and 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.

题意:给定由4和7组成的序列,有两个操作:(1) switch l f : 将区间[l,f]中的4变成7,7变成4    (2) count : 输出整个序列的最长上升子序列

解题思路: 这是一道中规中矩的线段树的题,对于每个线段树的结点需要维护四个值:序列中4的数目num4,序列中7的数目num7,最长上升序列大小rise,最长下降序列大小down。 合并操作:对于每个区间合并,num4和num7就不用我说了,rise取 左区间的num4+右区间的rise 与 左区间的rise+右区间的num7中的最大值,同理 down取 左区间num7+右区间down 与 左区间down+右区间的num4的最大值。直接看代码吧。

AC代码:

#include<bits/stdc++.h>
#define Mid ((l+r)>>1)
#define lson (rt<<1)+1,l,Mid
#define rson (rt<<1)+2,Mid+1,r
#define ll (rt<<1)+1
#define rr (rt<<1)+2
using namespace std;
const int MAX = 1000010;
char str[MAX];

struct Tree{
    int num4;
    int num7;
    int down;
    int rise;
}seg[(MAX<<2)+1];
int swi[(MAX<<2)+1];

void pushup(int rt)
{
    seg[rt].num4 = seg[ll].num4 + seg[rr].num4;
    seg[rt].num7 = seg[ll].num7 + seg[rr].num7;
    seg[rt].down = max(seg[ll].num7 + seg[rr].down, seg[ll].down + seg[rr].num4);
    seg[rt].rise = max(seg[ll].num4 + seg[rr].rise, seg[ll].rise + seg[rr].num7);
}

void build(int rt, int l, int r)
{
    swi[rt] = 0;
    if(l == r)
    {
        if(str[l] == '4')
        {
            seg[rt].num4=seg[rt].rise=seg[rt].down = 1;
            seg[rt].num7=0;
            return ;
        }
        else
        {
            seg[rt].num7=seg[rt].rise=seg[rt].down=1;
            seg[rt].num4 = 0;
            return ;
        }
    }
    else
    {
        build(lson);
        build(rson);
        pushup(rt);
    }
}

void pushDown(int rt)
{
    if(swi[rt] != 0)
    {
        swi[ll] += swi[rt];
        swi[rr] += swi[rt];
        if(swi[rt]&1)
        {
            swap(seg[ll].num4,seg[ll].num7);
            swap(seg[ll].rise,seg[ll].down);
            swap(seg[rr].num4,seg[rr].num7);
            swap(seg[rr].rise,seg[rr].down);
        }
        swi[rt] = 0;
    }
}

void update(int rt, int l, int r, int L, int R)
{
    if(L <= l && R >= r)
    {
        swi[rt] += 1;
        swap(seg[rt].num4,seg[rt].num7);
        swap(seg[rt].rise,seg[rt].down);
    }
    else
    {
        pushDown(rt);
        if(L <= Mid)
            update(lson,L,R);
        if(R > Mid)
            update(rson,L,R);
        pushup(rt);
    }
}

int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        scanf("%s",str);
        //memset(swi,0,sizeof(swi));
        build(0,0,n-1);
        char input[10];
        int l,r;
        for(int i=0; i<m; i++)
        {
            scanf("%s",input);
            if(input[0] == 's')
            {
                scanf("%d %d",&l,&r);
                update(0,0,n-1,l-1,r-1);
            }
            else
            {
                printf("%d
",seg[0].rise);
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/MyCodeLife-/p/8675738.html