【线段树】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, b]

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

不太熟悉异或操作

用两种标记 col表示 区间变成0/1  ; ox表示 区间异或

0 1 操作跟普通线段树一样

异或操作需要 ox[rt]^=1;

......搞了一个晚上 错这里了..

4 操作普通的区间合并啦

lsum记录左边开始连续的1的个数 rsum记录右边开始连续的1的个数

zero就记录连续的0啦

还有在延迟的时候需要先pushdown   col标记  再 pushdown ox标记

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <queue>
#include <stack>
#include <vector>
#include <deque>
#include <set>
#include <map>
#define IN     freopen ("in.txt" , "r" , stdin);
#define OUT  freopen ("out.txt" , "w" , stdout);
typedef long long  LL;
const int MAXN = 100110;//点数的最大值
const int MAXM = 20006;//边数的最大值
const int INF = 11521204;
const int mod=1000000007;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int num1[MAXN<<2],num2[MAXN<<2],ans[MAXN];
int sum[MAXN<<2],lsum[MAXN<<2],rsum[MAXN<<2];
int zero[MAXN<<2],lzero[MAXN<<2],rzero[MAXN<<2];
int col[MAXN<<2],ox[MAXN<<2];
void pushup(int rt,int m)
{
    int lx=m-(m>>1);
    int rx=(m>>1);
    //1的向上更新
    lsum[rt]=lsum[rt<<1];
    rsum[rt]=rsum[rt<<1|1];
    if(lsum[rt]==lx)  lsum[rt]+=lsum[rt<<1|1];
    if(rsum[rt]==rx)  rsum[rt]+=rsum[rt<<1];
    sum[rt]=max(max(sum[rt<<1],sum[rt<<1|1]),rsum[rt<<1]+lsum[rt<<1|1]);
    //0的向上更新
    lzero[rt]=lzero[rt<<1];
    rzero[rt]=rzero[rt<<1|1];
    if(lzero[rt]==lx)  lzero[rt]+=lzero[rt<<1|1];
    if(rzero[rt]==rx)  rzero[rt]+=rzero[rt<<1];
    zero[rt]=max(max(zero[rt<<1],zero[rt<<1|1]),rzero[rt<<1]+lzero[rt<<1|1]);
    //总数的更新
    num1[rt]=num1[rt<<1]+num1[rt<<1|1];
    num2[rt]=num2[rt<<1]+num2[rt<<1|1];
}
void pushdown(int rt,int m,int l,int r)
{
    if(col[rt]!=-1)
    {
        ox[rt<<1]=ox[rt<<1|1]=0;
        col[rt<<1]=col[rt<<1|1]=col[rt];
        sum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=col[rt]?m-(m>>1):0;
        sum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=col[rt]?m>>1:0;
        zero[rt<<1]=lzero[rt<<1]=rzero[rt<<1]=col[rt]?0:m-(m>>1);
        zero[rt<<1|1]=lzero[rt<<1|1]=rzero[rt<<1|1]=col[rt]?0:m>>1;
        num1[rt<<1]=col[rt]? m-(m>>1):0;
        num2[rt<<1]=col[rt]?0:m-(m>>1);
        num1[rt<<1|1]=col[rt]?m>>1:0;
        num2[rt<<1|1]=col[rt]?0:m>>1;
        col[rt]=-1;
    }
    if(ox[rt])
    {
        ox[rt<<1]^=1;
        ox[rt<<1|1]^=1;
        swap(sum[rt<<1],zero[rt<<1]);
        swap(sum[rt<<1|1],zero[rt<<1|1]);
        swap(lsum[rt<<1],lzero[rt<<1]);
        swap(lsum[rt<<1|1],lzero[rt<<1|1]);
        swap(rsum[rt<<1],rzero[rt<<1]);
        swap(rsum[rt<<1|1],rzero[rt<<1|1]);
        swap(num1[rt<<1],num2[rt<<1]);
        swap(num1[rt<<1|1],num2[rt<<1|1]);
        ox[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    col[rt]=-1;
    ox[rt]=0;
    if(l==r)
    {
        scanf("%d",&num1[rt]);
        if(num1[rt])
        {
            num2[rt]=0;
            sum[rt]=lsum[rt]=rsum[rt]=1;
            zero[rt]=lzero[rt]=rzero[rt]=0;
        }
        else
        {
            sum[rt]=lsum[rt]=rsum[rt]=0;
            zero[rt]=lzero[rt]=rzero[rt]=1;
            num2[rt]=1;
        }
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt,r-l+1);
}
void update(int L,int R,int c,int l,int r,int rt)//更新  0 1 2 分别表示区间更新为0 , 1,异或
{
    if(L<=l&&r<=R)
    {
        if(c==2)//异或
        {
            swap(num1[rt],num2[rt]);//0 1 个数交换
            swap(sum[rt],zero[rt]);
            swap(lsum[rt],lzero[rt]);
            swap(rsum[rt],rzero[rt]);
            ox[rt]^=1;
        }
        else
        {
            sum[rt]=lsum[rt]=rsum[rt]=c==1?r-l+1:0;
            zero[rt]=lzero[rt]=rzero[rt]=c==1?0:r-l+1;
            num1[rt]=c==1?r-l+1:0;
            num2[rt]=c==1?0:r-l+1;
            col[rt]=c;
            ox[rt]=0;
        }
        return ;
    }
    int m=(l+r)>>1;
    pushdown(rt,r-l+1,l,r);
    if(L<=m)    update(L,R,c,lson);
    if(m<R)      update(L,R,c,rson);
    pushup(rt,r-l+1);
}
int query1(int L,int R,int l,int r,int rt)//输出1的个数
{
    if(L<=l&&r<=R)
    {
        return num1[rt];
    }
    int m=(l+r)>>1,res=0;
    pushdown(rt,r-l+1,l,r);
    if(L<=m)    res+=query1(L,R,lson);
    if(m<R)    res+=query1(L,R,rson);
    return res;
}
int query2(int L,int R,int l,int r,int rt)//输出连续的
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int m=(l+r)>>1,res=0;
    pushdown(rt,r-l+1,l,r);
    if(L<=m)    res=max(res, query2(L,R,lson));
    if(m<R)    res=max(res,query2(L,R,rson));
    res = max(res, min(m-L+1, rsum[rt<<1])+min(R-m, lsum[rt<<1|1]));
    return res;
}
int main()
{
    int n,m,t;
   //IN;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        build(1,n,1);
        while(m--)
        {
            int a,b,c;
            scanf("%d%d%d",&c,&a,&b);
            a++,b++;
            if(c <=2)
                update(a,b,c,1,n,1);
            else
            {
                if(c==3)
                    printf("%d\n",query1(a,b,1,n,1));
                else printf("%d\n",query2(a,b,1,n,1));
            }
        }
    }
    return 0;
}
/*
1
4 3
0 0 1 1
1 1 2
2 1 2
3 1 1
*/

【线段树】HDU 3397 Sequence operation 区间合并

时间: 2024-12-21 09:26:05

【线段树】HDU 3397 Sequence operation 区间合并的相关文章

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 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(线段树&#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

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(线段树,区间染色+区间异或+区间合并)

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

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(线段树:区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给你一个长度为n的0,1序列,支持下列五种操作, 操作0(0 a b):将a到b这个区间的元素全部置为0. 操作1(1 a b):将a到b这个区间的元素全部置为1. 操作2(2 a b):将a到b这个区间所有的0置为1,所有的1置为0. 操作3(3 a b):查询a到b这个区间1的总数. 操作4(4 a b):查询a到b这个区间连续1的最长长度 本题属于简单的区间更新线段树 重点:0操作

HDU 3397 Sequence operation(区间合并 + 区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3397 题意:给定n个数,由0,1构成.共有5种操作.每个操作输入3个数,op,a,b. op == 0,将区间[a,b]赋值为0: op == 1,将区间[a,b]赋值为1: op == 2,将区间[a,b]内的01反转: op == 3,查询区间[a,b]中1的个数: op == 4,查询区间[a,b]中连续1的最大长度: 思路:区间合并 + 区间更新.每个结点存7个数: 区间内1的个数c1. 从