codeforces 145 E. Lucky Queries (线段树lazy标记)

题目链接

题意:给出一串只由数字'4'和'7'组成的串。两种操作,一种是询问整个串中最长非下降子序列的长度,另一种给出区间[l,r],将区间中的没个数反转,反转的定义为,4变成7,7变成4.

思路:线段树lazy标记。

线段树的域记录5个信息,c4,c7,c47,c74,flip,a分别表示4的个数,7的个数,非下降子序列的个数,非上升的子序列的个数,以及该区间是否被翻转。

纠结了很久PushUp操作。。。。

c4和c7倒是没什么疑问。。。。

一开始觉得c47是由三部分的最大值更新得到的。。。

left.c4+right.c47,left.c4+right.c7,left.c47+right.c7...

但是样例过不了。。。

纠结了半天发现。。。

比如4774,4444是左右两个区间的时候。。。。

c47最大是5.。。但是left.c4 + right.c7=6,比正确答案大。

原因是。。一个区间中4的位置可能是分散的。。。这样只有某段连续出现的4对答案的贡献是正确的。。。

所以只有区间长度为1的时候c4+c7的更新方式才是合法的。。。

我们不妨在初始化的时候。。。。在线段树的叶子节点直接设置c47为1(当然相应地c74也要为1)

另外一个收获是。。。线段树对于区间的操作(对于点的操作也是同样)

不一定是某种常见的定义过的操作(求和啊,最大值最小值啊之类的)

也可能是某种自定义的操作。。。

比如这道题中的flip操作。。。

就是对区间的一个自定义的操作。。。

  1/* ***********************************************
  2Author :111qqz
  3Created Time :Tue 27 Sep 2016 09:14:22 AM CST
  4File Name :code/cf/problem/145E.cpp
  5 ************************************************ */
  6#include <cstdio>
  7#include <cstring>
  8#include <iostream>
  9#include <algorithm>
 10#include <vector>
 11#include <queue>
 12#include <set>
 13#include <map>
 14#include <string>
 15#include <cmath>
 16#include <cstdlib>
 17#include <ctime>
 18#define fst first
 19#define sec second
 20#define lson l,m,rt<<1
 21#define rson m+1,r,rt<<1|1
 22#define ms(a,x) memset(a,x,sizeof(a))
 23typedef long long LL;
 24#define pi pair < int ,int >
 25#define MP make_pair
 26using namespace std;
 27const double eps = 1E-8;
 28const int dx4[4]={1,0,0,-1};
 29const int dy4[4]={0,-1,1,0};
 30const int inf = 0x3f3f3f3f;
 31const int N = 1E6+7;
 32int n,m;
 33char st[N];
 34struct node
 35{
 36    int c7,c4,c47,c74;
 37    bool flip;
 38    void out()
 39    {
 40	printf("c4:%d c7: %d c47 :%d c74 : %d\n",c4,c7,c47,c74);
 41    }
 42}tree[N<<2];
 43void PushUp( int rt)
 44{
 45    tree[rt].c4 = tree[rt<<1].c4 + tree[rt<<1|1].c4;
 46    tree[rt].c7 = tree[rt<<1].c7 + tree[rt<<1|1].c7;
 47    tree[rt].c47 = max(tree[rt<<1].c4 + tree[rt<<1|1].c47 , tree[rt<<1].c47 + tree[rt<<1|1].c7);
 48    tree[rt].c74 = max(tree[rt<<1].c7 + tree[rt<<1|1].c74, tree[rt<<1].c74 + tree[rt<<1|1].c4);
 49}
 50void build( int l,int r ,int rt)
 51{
 52    if (l==r)
 53    {
 54	if (st[l-1]=='4') tree[rt].c4 = 1;
 55	else tree[rt].c7 = 1;
 56	tree[rt].c47 = tree[rt].c74 = 1;
 57	return;
 58    }
 59    int m = (l+r)>>1;
 60    build(lson);
 61    build(rson);
 62    PushUp(rt);
 63}
 64void Flip( int rt)
 65{
 66    tree[rt].flip^=1;
 67    swap(tree[rt].c4,tree[rt].c7);
 68    swap(tree[rt].c47,tree[rt].c74);
 69}
 70void PushDown( int rt)
 71{
 72    if (tree[rt].flip)
 73    {
 74	Flip(rt<<1);
 75	Flip(rt<<1|1);
 76	tree[rt].flip = 0 ;
 77    }
 78}
 79void update(int L,int R,int l,int r,int rt)
 80{
 81    if (L<=l&&r<=R)
 82    {
 83	Flip(rt);
 84	return;
 85    }
 86    PushDown(rt);
 87    int m = (l+r)>>1;
 88    if (L<=m) update(L,R,lson);
 89    if (R>=m+1)  update(L,R,rson);
 90    PushUp(rt);
 91}
 92int main()
 93{
 94#ifndef  ONLINE_JUDGE 
 95    freopen("code/in.txt","r",stdin);
 96#endif
 97    scanf("%d%d",&n,&m);
 98    scanf("%s",st);
 99    build(1,n,1);
100    while (m--)
101    {
102	char opt[10];
103	scanf("%s",opt);
104	//  cout<<"opt:"<<opt<<endl;
105	if (opt[0]=='c')
106	{
107	    printf("%d\n",tree[1].c47);
108	}
109	else
110	{
111	    int x,y;
112	    scanf("%d%d",&x,&y);
113	    update(x,y,1,n,1);
114	}
115    }
116#ifndef ONLINE_JUDGE  
117    fclose(stdin);
118#endif
119    return 0;
120}