HDU 3397——Sequence operation(线段树,区间染色+区间异或+区间合并)

Sequence operation

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

Total Submission(s): 6270    Accepted Submission(s): 1862

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

———————————————————————分割线————————————————

题目大意:

给定一个n个数的序列,有5种操作

1: 0 a b 将区间[a,b]覆盖为0

2:1 a b 将区间[a,b]覆盖为1

3:2 a b 将区间[a,b] 0变成1,1变成0

4:3 a b 查询区间[a,b]1的个数

5:4 a b 查询区间[a,b]连续1的个数

思路:

push_up 维护:

左连续,右连续,总连续的0/1的个数

总的1的个数

push_down lazy标记:

覆盖标记,异或标记

当某节点的信息被修改时,要push_up,对于异或标记和覆盖标记 要优先考虑覆盖标记,再考虑异或标记

查找区间的时候要push_down

细节好重要!!!加深理解push_up,push_down

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

const int maxn=100001;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int lc[maxn<<2],rc[maxn<<2],mc[maxn<<2];
int lc0[maxn<<2],rc0[maxn<<2],mc0[maxn<<2];
int cov[maxn<<2],Xor[maxn<<2],sum[maxn<<2];

void f_xor(int rt,int m)
{
    if(cov[rt]!=-1) cov[rt]^=1;
    else Xor[rt]^=1;
    swap(lc[rt],lc0[rt]);
    swap(rc[rt],rc0[rt]);
    swap(mc[rt],mc0[rt]);
    sum[rt]=m-sum[rt];
}
void f_cov(int rt,int m,int c)
{
    cov[rt]=c;
    Xor[rt]=0;
    lc0[rt]=rc0[rt]=mc0[rt]=c ?0:m;
    lc[rt]=rc[rt]=mc[rt]=sum[rt]=c ? m:0;
}
void push_down(int rt,int m)
{
    if(cov[rt]!=-1) {
        f_cov(rt<<1,m-(m>>1),cov[rt]);
        f_cov(rt<<1|1,m>>1,cov[rt]);
        cov[rt]=-1;
        Xor[rt]=0;
    }
    if(Xor[rt]) {
        f_xor(rt<<1,m-(m>>1));
        f_xor(rt<<1|1,m>>1);
        Xor[rt]=0;
    }
}
void push_up(int rt,int m)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];

    lc[rt]=lc[rt<<1];
    rc[rt]=rc[rt<<1|1];
    if(lc[rt]==m-(m>>1))
        lc[rt]+=lc[rt<<1|1];
    if(rc[rt]==m>>1)
        rc[rt]+=rc[rt<<1];
    mc[rt]=max(rc[rt<<1]+lc[rt<<1|1],max(mc[rt<<1],mc[rt<<1|1]));

    lc0[rt]=lc0[rt<<1];
    rc0[rt]=rc0[rt<<1|1];
    if(lc0[rt]==m-(m>>1))
        lc0[rt]+=lc0[rt<<1|1];
    if(rc0[rt]==m>>1)
        rc0[rt]+=rc0[rt<<1];
    mc0[rt]=max(lc0[rt<<1|1]+rc0[rt<<1],max(mc0[rt<<1],mc0[rt<<1|1]));
}
void build(int l,int r,int rt)
{
    cov[rt]=-1;
    Xor[rt]=0;
    if(l==r) {
        scanf("%d",&sum[rt]);
        cov[rt]=lc[rt]=rc[rt]=mc[rt]=sum[rt];
        lc0[rt]=rc0[rt]=mc0[rt]= 1-sum[rt];
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    push_up(rt,r-l+1);
}
void update(int op,int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) {
        if(op==0)
            f_cov(rt,r-l+1,0);
        if(op==1)
            f_cov(rt,r-l+1,1);
        if(op==2)
            f_xor(rt,r-l+1);
        return ;
    }
    push_down(rt,r-l+1);
    int m=(l+r)>>1;
    if(L<=m) update(op,L,R,lson);
    if(m<R) update(op,L,R,rson);
    push_up(rt,r-l+1);
}
int query_sum(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) {
        return sum[rt];
    }
    push_down(rt,r-l+1);
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m)
        ans+=query_sum(L,R,lson);
    if(m<R)
        ans+=query_sum(L,R,rson);
    return ans;
}
int query_len(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R) {
        return mc[rt];
    }
    push_down(rt,r-l+1);
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m)
        ans=max(ans,query_len(L,R,lson));
    if(m<R)
        ans=max(ans,query_len(L,R,rson));
    return max(ans,min(m-L+1,rc[rt<<1])+min(R-m,lc[rt<<1|1]));
}
int main()
{
    int T,n,m;
    cin>>T;
    while(T--) {
        scanf("%d %d",&n,&m);
        build(0,n-1,1);
        int op,l,r;
        while(m--) {
            scanf("%d %d %d",&op,&l,&r);
            if(op<=2)
                update(op,l,r,0,n-1,1);
            if(op==3)
                printf("%d\n",query_sum(l,r,0,n-1,1));
            if(op==4)
                printf("%d\n",query_len(l,r,0,n-1,1));
        }
    }
    return 0;
}
时间: 2024-12-13 00:17:47

HDU 3397——Sequence operation(线段树,区间染色+区间异或+区间合并)的相关文章

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 线段树

线段树大杂烩~ 各种操作都有,细心点不难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 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问区间1的个数 4.询问区间被最长连续1的长度 思路: 这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表

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 线段树 区间更新 区间合并

题意: 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 区间合并

操作 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,

HDU 3397 Sequence operation(线段树)

HDU 3397 Sequence operation 题目链接 题意:给定一个01序列,有5种操作 0 a b [a.b]区间置为0 1 a b [a,b]区间置为1 2 a b [a,b]区间0变成1,1变成0 3 a b 查询[a,b]区间1的个数 4 a b 查询[a,b]区间连续1最长的长度 思路:线段树线段合并.须要两个延迟标记一个置为01,一个翻转,然后因为4操作,须要记录左边最长0.1.右边最长0.1,区间最长0.1,然后区间合并去搞就可以 代码: #include <cstdi

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------

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