(简单) HDU 3397 Sequence operation,线段树+区间合并。

  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]

  典型的水题,对一段01序列进行区间覆盖和反转,维护1的个数,连续1的个数,前缀1的个数,后缀1的个数,以及连续0,前缀0,后缀0,用来计算反转时的1.

  不过还是写错了个地方,在程序里面标记出来了。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>

#define lc po*2
#define rc po*2+1
#define lson L,M,lc
#define rson M+1,R,rc

using namespace std;

const int maxn=1e5+5;

int sum[maxn*4],lsum[2][maxn*4],rsum[2][maxn*4],msum[2][maxn*4];
int COL[maxn*4],XOR[maxn*4];

inline void swap(int &a,int &b)
{
    int temp=a;
    a=b;
    b=temp;
}

void pushUP(int po,int len)
{
    sum[po]=sum[lc]+sum[rc];

    for(int i=0;i<2;++i)
    {
        msum[i][po]=max(msum[i][lc],msum[i][rc]);
        msum[i][po]=max(msum[i][po],lsum[i][rc]+rsum[i][lc]);

        lsum[i][po]=lsum[i][lc];
        if(lsum[i][lc]==(len-(len/2)))
            lsum[i][po]+=lsum[i][rc];

        rsum[i][po]=rsum[i][rc];
        if(rsum[i][rc]==(len/2))
            rsum[i][po]+=rsum[i][lc];
    }
}

void pushDown(int po,int len)
{
    if(COL[po]!=-1)
    {
        COL[lc]=COL[rc]=COL[po];
        XOR[lc]=XOR[rc]=0;

        sum[lc]=COL[po]*(len-(len/2));
        sum[rc]=COL[po]*(len/2);

        for(int i=0;i<2;++i)
        {
            msum[i][lc]=lsum[i][lc]=rsum[i][lc]=(i ? sum[lc] : len-(len/2)-sum[lc]);
            msum[i][rc]=rsum[i][rc]=lsum[i][rc]=(i ? sum[rc] : (len/2)-sum[rc]);
        }

        COL[po]=-1;
    }

    if(XOR[po])
    {
        XOR[lc]=!XOR[lc];
        XOR[rc]=!XOR[rc];

        sum[lc]=len-(len/2)-sum[lc];
        sum[rc]=(len/2)-sum[rc];

        swap(msum[0][lc],msum[1][lc]);
        swap(msum[0][rc],msum[1][rc]);

        swap(lsum[0][lc],lsum[1][lc]);
        swap(rsum[0][lc],rsum[1][lc]);

        swap(lsum[0][rc],lsum[1][rc]);
        swap(rsum[0][rc],rsum[1][rc]);

        XOR[po]=0;
    }
}

void build_tree(int L,int R,int po)
{
    COL[po]=-1;
    XOR[po]=0;

    if(L==R)
    {
        int temp;
        scanf("%d",&temp);

        sum[po]=temp;
        lsum[0][po]=rsum[0][po]=msum[0][po]=1-temp;
        lsum[1][po]=rsum[1][po]=msum[1][po]=temp;

        return;
    }

    int M=(L+R)/2;

    build_tree(lson);
    build_tree(rson);

    pushUP(po,R-L+1);
}

void update_col(int ul,int ur,int ut,int L,int R,int po)
{
    if(ul<=L&&ur>=R)
    {
        COL[po]=ut;
        XOR[po]=0;

        sum[po]=ut*(R-L+1);
        lsum[1][po]=rsum[1][po]=msum[1][po]=sum[po];
        lsum[0][po]=rsum[0][po]=msum[0][po]=R-L+1-sum[po];

        return;
    }

    pushDown(po,R-L+1);

    int M=(L+R)/2;

    if(ul<=M)
        update_col(ul,ur,ut,lson);
    if(ur>M)
        update_col(ul,ur,ut,rson);

    pushUP(po,R-L+1);
}

void update_xor(int ul,int ur,int L,int R,int po)
{
    if(ul<=L&&ur>=R)
    {
        XOR[po]=!XOR[po];

        sum[po]=R-L+1-sum[po];
        swap(msum[0][po],msum[1][po]);
        swap(lsum[0][po],lsum[1][po]);
        swap(rsum[0][po],rsum[1][po]);

        return;
    }

    pushDown(po,R-L+1);

    int M=(L+R)/2;

    if(ul<=M)
        update_xor(ul,ur,lson);
    if(ur>M)
        update_xor(ul,ur,rson);

    pushUP(po,R-L+1);
}

int query_sum(int ql,int qr,int L,int R,int po)
{
    if(ql<=L&&qr>=R)
        return sum[po];

    pushDown(po,R-L+1);

    int M=(L+R)/2;

    if(qr<=M)
        return query_sum(ql,qr,lson);
    if(ql>M)
        return query_sum(ql,qr,rson);

    return query_sum(ql,qr,lson)+query_sum(ql,qr,rson);
}

int query_max(int ql,int qr,int L,int R,int po)
{
    if(ql<=L&&qr>=R)
        return msum[1][po];

    pushDown(po,R-L+1);

    int M=(L+R)/2;
    int ans=0;

    if(qr<=M)
        return query_max(ql,qr,lson);
    if(ql>M)
        return query_max(ql,qr,rson);

    ans=max(query_max(ql,qr,lson),query_max(ql,qr,rson));
    ans=max(ans,min(rsum[1][lc],M-ql+1)+min(lsum[1][rc],qr-M));            //!!!

    return ans;
}

int main()
{
    int T;
    int N,M;
    int a,b,c;
    cin>>T;

    while(T--)
    {
        scanf("%d %d",&N,&M);

        build_tree(0,N-1,1);

        while(M--)
        {
            scanf("%d %d %d",&a,&b,&c);

            switch(a)
            {
                case 0:
                    update_col(b,c,0,0,N-1,1);
                    break;
                case 1:
                    update_col(b,c,1,0,N-1,1);
                    break;
                case 2:
                    update_xor(b,c,0,N-1,1);
                    break;
                case 3:
                    printf("%d\n",query_sum(b,c,0,N-1,1));
                    break;
                case 4:
                    printf("%d\n",query_max(b,c,0,N-1,1));
                    break;
            }
        }
    }

    return 0;
}

时间: 2024-08-02 19:08:11

(简单) HDU 3397 Sequence operation,线段树+区间合并。的相关文章

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

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

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

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 3308 LCIS,线段树+区间合并。

Problem Description Given n integers. You have two operations: U A B: replace the Ath number by B. (index counting from 0) Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b]. 题目大意就是给你一个数列,求区间内的最长连续子序列.以及对某一个点的

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability

Sequence operation(线段树区间多种操作)

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

HDU 5316——Magician——————【线段树区间合并区间最值】

Magician Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1613    Accepted Submission(s): 470 Problem Description Fantasy magicians usually gain their ability through one of three usual methods:

HDU - 3308 - LCIS (线段树 - 区间合并)

题目传送:LCIS 线段树,区间合并,一次过啦,没有纠结,这几天过的最愉快的一个题 思路:求最长连续上升子序列,外带单点更新,经典的线段树题目.具体看代码注释 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack>