HDU 3397 Sequence operation (线段树,成段更新,区间合并)

http://acm.hdu.edu.cn/showproblem.php?pid=3397

Sequence operation

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 5801    Accepted Submission(s): 1713

Problem Description

lxhgww got a sequence contains n characters which are all ‘0‘s or ‘1‘s.

We have five operations here:

Change operations:

0 a b change all characters into ‘0‘s in [a , b]

1 a b change all characters into ‘1‘s in [a , b]

2 a b change all ‘0‘s into ‘1‘s and change all ‘1‘s into ‘0‘s in [a, b]

Output operations:

3 a b output the number of ‘1‘s in [a, b]

4 a b output the length of the longest continuous ‘1‘ string in [a , b]

Input

T(T<=10) in the first line is the case number.

Each case has two integers in the first line: n and m (1 <= n , m <= 100000).

The next line contains n characters, ‘0‘ or ‘1‘ separated by spaces.

Then m lines are the operations:

op a b: 0 <= op <= 4 , 0 <= a <= b < n.

Output

For each output operation , output the result.

Sample Input

1
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9

Sample Output

5
2
6
5

Author

lxhgww&&shǎ崽

Source

HDOJ Monthly Contest – 2010.05.01

表示再也不想看到线段树了>_<

题意:

0 a b:将区间[a,b]全部置为0;

1 a b:将区间[a,b]全部置为1;

2 a b:对区间[a,b]进行异或操作;

3 a b:询问区间[a,b]内有多少个1;

4 a b:询问区间[a,b]内最长连续的1有多长。

分析:

置0/1很简单成段更新lazy一下就行了,询问有多少个1就是个求和,维护区间内和值即可。询问最长连续的1是个区间合并,我们要维护3个值,区间左顶点开始的最长连续1,右顶点开始的最长联系1,区间内的最长连续1,这样维护父节点的时候要注意他的左右孩子是否连续。

异或操作就比较复杂,我们不仅要维护1的信息,还要维护0的信息。如果该区间内的值相同(setv!=-1),那么setv^=1并且交换0/1信息的值,否则XOR^=1并且交换0/1信息的值。pushdown有些麻烦,如果setv[k]!=-1(k是当前节点,lc是左孩子,rc是右孩子),那么他两个孩子之前的异或操作都会被覆盖掉,所以下传setv[k],并将两个孩子的XOR标记清空;如果XOR[k]==1,那么将两个孩子自身的0/1信息互换并将XOR下传给左右孩子。

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#include<cctype>
#include<cmath>
#include<string>
#include<cstring>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<map>
#include<set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10
#define maxm
#define maxn 100007

using namespace std;

int XOR[maxn<<2],setv[maxn<<2],lm1[maxn<<2],rm1[maxn<<2],lm0[maxn<<2],rm0[maxn<<2],sum[maxn<<2],msum1[maxn<<2],msum0[maxn<<2];

inline void SWAP(int k,int l,int r)
{
    swap(lm1[k],lm0[k]);swap(rm1[k],rm0[k]);swap(msum1[k],msum0[k]);sum[k]=r-l-sum[k];
}

inline void pushup(int k,int l,int r)
{
    int lc=k*2+1,rc=k*2+2,m=l+r>>1;

    sum[k]=sum[lc]+sum[rc];

    if (lm1[lc]==m-l)   lm1[k]=lm1[lc]+lm1[rc]; else    lm1[k]=lm1[lc];
    if (rm1[rc]==r-m)   rm1[k]=rm1[rc]+rm1[lc]; else    rm1[k]=rm1[rc];
    msum1[k]=max(rm1[lc]+lm1[rc],max(msum1[lc],msum1[rc]));

    if (lm0[lc]==m-l)   lm0[k]=lm0[lc]+lm0[rc]; else    lm0[k]=lm0[lc];
    if (rm0[rc]==r-m)   rm0[k]=rm0[rc]+rm0[lc]; else    rm0[k]=rm0[rc];
    msum0[k]=max(rm0[lc]+lm0[rc],max(msum0[lc],msum0[rc]));

}

inline void pushdown(int k,int l,int r)
{
    int lc=k*2+1,rc=k*2+2,m=l+r>>1;
    if (setv[k]!=-1)
    {
        setv[lc]=setv[rc]=setv[k];
        XOR[lc]=XOR[rc]=0;

        lm1[lc]=rm1[lc]=msum1[lc]=sum[lc]=setv[k]?m-l:0;
        lm0[lc]=rm0[lc]=msum0[lc]=setv[k]?0:m-l;

        lm1[rc]=rm1[rc]=msum1[rc]=sum[rc]=setv[k]?r-m:0;
        lm0[rc]=rm0[rc]=msum0[rc]=setv[k]?0:r-m;

        setv[k]=-1;
    }

    if (XOR[k])
    {
        if (setv[lc]!=-1)   setv[lc]^=1;    else    XOR[lc]^=1;
        if (setv[rc]!=-1)   setv[rc]^=1;    else    XOR[rc]^=1;
        SWAP(lc,l,m);SWAP(rc,m,r);
        XOR[k]=0;
    }
}

void update(int a,int b,int v,int k,int l,int r)
{
    if (b<=l || r<=a)   return ;
    if (a<=l && r<=b)
    {
        setv[k]=v;
        lm1[k]=rm1[k]=msum1[k]=sum[k]=v?r-l:0;
        lm0[k]=rm0[k]=msum0[k]=v?0:r-l;
        XOR[k]=0;
    }
    else
    {
        pushdown(k,l,r);
        int m=l+r>>1;
        update(a,b,v,k*2+1,l,m);
        update(a,b,v,k*2+2,m,r);
        pushup(k,l,r);
    }
}

void change(int a,int b,int k,int l,int r)
{
    if (b<=l || r<=a)   return ;
    if (a<=l && r<=b)
    {
        if (setv[k]!=-1)
            setv[k]^=1;
        else
            XOR[k]^=1;

        SWAP(k,l,r);
    }
    else
    {
        pushdown(k,l,r);
        int m=l+r>>1;
        change(a,b,k*2+1,l,m);
        change(a,b,k*2+2,m,r);
        pushup(k,l,r);
    }
}

int query_sum(int a,int b,int k,int l,int r)
{
    if (b<=l || r<=a)   return 0;

    if (a<=l && r<=b) return sum[k];

    if (r-l!=1) pushdown(k,l,r);

    int m=l+r>>1,v1=0,v2=0;

    v1=query_sum(a,b,k*2+1,l,m);
    v2=query_sum(a,b,k*2+2,m,r);

    return v1+v2;
}

int query_lc1(itn a,int b,int k,int l,int r)
{
    if (b<=l || r<=a)   return 0;

    if (a<=l && r<=b)   return msum1[k];

    if (r-l!=1) pushdown(k,l,r);

    int m=l+r>>1,v1=0,v2=0,v3=0;

    v1=query_lc1(a,b,k*2+1,l,m);
    v2=query_lc1(a,b,k*2+2,m,r);
    v3=min(b,m+lm1[k*2+2])-max(a,m-rm1[k*2+1]);

    return max(v3,max(v1,v2));
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("/home/fcbruce/文档/code/t","r",stdin);
    #endif // ONLINE_JUDGE

    int T_T,n,m,x,a,b,op;
    scanf("%d",&T_T);

    while (T_T--)
    {
        scanf("%d %d",&n,&m);
        for (int i=0;i<n;i++)
        {
            scanf("%d",&x);
            update(i,i+1,x,0,0,n);
        }

        while (m--)
        {
            scanf("%d %d %d",&op,&a,&b);

            if (op==0)
            {
                update(a,b+1,0,0,0,n);
                continue;
            }

            if (op==1)
            {
                update(a,b+1,1,0,0,n);
                continue;
            }

            if (op==2)
            {
                change(a,b+1,0,0,n);
                continue;
            }

            if (op==3)
            {
                printf("%d\n",query_sum(a,b+1,0,0,n));
                continue;
            }

            if (op==4)
            {
                printf("%d\n",query_lc1(a,b+1,0,0,n));
                continue;
            }
        }
    }

    return 0;
}
时间: 2024-08-04 01:56:35

HDU 3397 Sequence operation (线段树,成段更新,区间合并)的相关文章

HDU 3397 Sequence operation(线段树&#183;成段更新&#183;区间合并&#183;混合操作)

题意  给你一个只有0, 1的数组  有这些操作 0. 将[a, b]区间的所有数都改为0 1. 将[a, b]区间的所有数都改为1 2. 将[a, b]区间的所有数都取反 即与1异或 3. 输出区间[a, b]中1的个数  即所有数的和 4. 输出区间[a, b]中最大连续1的长度 对于所有的3, 4操作输出对应的答案 单个的操作都很简单  但搞在一起就有点恶心了  还好数组里的数只有0和1 线段树维护9个值 对应区间0, 1的最大长度len[i]  对应区间左端点为起点的最大0, 1长度ll

poj 3669 线段树成段更新+区间合并

添加 lsum[ ] , rsum[ ] , msum[ ] 来记录从左到右的区间,从右到左的区间和最大的区间: #include<stdio.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 50005 int rsum[maxn<<2],lsum[maxn<<2],msum[maxn<<2];//msum[]维护区间1…N中的最大连续区间长度 int

HDU 3397 Sequence operation 线段树

线段树大杂烩~ 各种操作都有,细心点不难1A #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; #define lson rt<<1,l,mid #define rson rt<<1|1,mid + 1,r const int maxn = 1e5 + 10; int lmax[maxn

POJ训练计划2777_Count Color(线段树/成段更新/区间染色)

解题报告 题意: 对线段染色,询问线段区间的颜色种数. 思路: 本来直接在线段树上染色,lz标记颜色.每次查询的话访问线段树,求出颜色种数.结果超时了,最坏的情况下,染色可以染到叶子节点. 换成存下区间的颜色种数,这样每次查询就不用找到叶子节点了,用按位或来处理颜色种数. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace

Hdu 3397 Sequence operation(线段树多操作,Lazy思想,成段更新)

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6397    Accepted Submission(s): 1899 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1

hdu 3397 Sequence operation (线段树 区间合并 多重标记)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问区间1的个数 4.询问区间被最长连续1的长度 思路: 这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表

hdu 3397 Sequence operation 线段树 区间更新 区间合并

题意: 5种操作,所有数字都为0或1 0 a b:将[a,b]置0 1 a b:将[a,b]置1 2 a b:[a,b]中的0和1互换 3 a b:查询[a,b]中的1的数量 4 a b:查询[a,b]中的最长连续1串的长度 这题看题目就很裸,综合了区间更新,区间合并 我一开始把更新操作全放一个变量,但是在push_down的时候很麻烦,情况很多,容易漏,后来改成下面的 更新的操作可以分为两类,一个是置值(stv),一个是互换(swp).如果stv!=-1,则更新儿子节点的stv,并将儿子的sw

(线段树成段更新+区间求和) poj 3468

D - A Simple Problem with Integers Time Limit:5000MS     Memory Limit:131072KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3468 Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One typ

线段树(成段更新) HDU 1698 Just a Hook

题目传送门 1 /* 2 线段树-成段更新:第一题!只要更新区间,输出总长度就行了 3 虽然是超级裸题,但是用自己的风格写出来,还是很开心的:) 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cmath> 8 #include <cstring> 9 #include <string> 10 #include <iostream> 11 using namesp