HDU3397: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]
 

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


 

题意:0,1,2,代表操作,0代表将区间内全部变为0,1代表区间内全部变为1,2代表区间内0,1取反

3,4代表查询,3代表查询区间内1的总数,4代表查询区间内最长连续1的个数

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define lc l,mid,2*i
#define rc mid+1,r,2*i+1
#define lson 2*i
#define rson 2*i+1
const int L = 100000+10;
int n,m;
int s[L];
struct node
{
    int l,r;
    int ls0,rs0,ms0;//左,右,最大连续0的个数
    int ls1,rs1,ms1;//左,右,最大连续1的个数
    int sum;//区间内1的总数
    int cover,x_or;//覆盖标记与异或标记
} a[L<<2];

void XOR(int i)//区间内0,1,变化就是将0,1有关的数据交换即可
{
    swap(a[i].ls0,a[i].ls1);
    swap(a[i].rs0,a[i].rs1);
    swap(a[i].ms0,a[i].ms1);
    a[i].sum = a[i].r-a[i].l+1-a[i].sum;//区间内的总数减去以前1的总数为变换后1的总数
}
void pushup(int i)//1,0都要更新
{
    if(a[i].l == a[i].r)
        return ;
    int len = a[i].r-a[i].l+1;
    a[i].ls0 = a[lson].ls0;
    a[i].rs0 = a[rson].rs0;
    if(a[lson].ls0 == a[lson].r-a[lson].l+1)
        a[i].ls0+=a[rson].ls0;
    if(a[rson].rs0 == a[rson].r-a[rson].l+1)
        a[i].rs0+=a[lson].rs0;
    a[i].ms0 = max(max(a[lson].ms0,a[rson].ms0),a[lson].rs0+a[rson].ls0);

    a[i].ls1 = a[lson].ls1;
    a[i].rs1 = a[rson].rs1;
    if(a[lson].ls1 == a[lson].r-a[lson].l+1)
        a[i].ls1+=a[rson].ls1;
    if(a[rson].rs1 == a[rson].r-a[rson].l+1)
        a[i].rs1+=a[lson].rs1;
    a[i].ms1 = max(max(a[lson].ms1,a[rson].ms1),a[lson].rs1+a[rson].ls1);

    a[i].sum = a[lson].sum+a[rson].sum;
}

void pushdown(int i)
{
    if(a[i].l == a[i].r)
        return;
    if(a[i].cover!=-1)//看区间是被0还是1覆盖了
    {
        int len = a[i].r-a[i].l+1;
        a[lson].cover = a[rson].cover = a[i].cover;
        a[lson].x_or = a[rson].x_or = 0;

        a[lson].ls0 = a[lson].rs0 = a[lson].ms0 = a[i].cover?0:(len+1)/2;
        a[lson].ls1 = a[lson].rs1 = a[lson].ms1 = a[i].cover?(len+1)/2:0;
        a[lson].sum = a[i].cover?(len+1)/2:0;

        a[rson].ls0 = a[rson].rs0 = a[rson].ms0 = a[i].cover?0:len/2;
        a[rson].ls1 = a[rson].rs1 = a[rson].ms1 = a[i].cover?len/2:0;
        a[rson].sum = a[i].cover?len/2:0;

        a[i].cover = -1;
    }
    if(a[i].x_or)
    {
        a[i].x_or = 0;
        a[lson].x_or^=1;
        a[rson].x_or^=1;
        XOR(lson);
        XOR(rson);
    }
}

void init(int l,int r,int i)
{
    a[i].l = l;
    a[i].r = r;
    a[i].cover = -1;
    a[i].x_or = 0;
    if(l==r)
    {
        a[i].ls0 = a[i].rs0 = a[i].ms0 = (s[l]==0);
        a[i].ls1 = a[i].rs1 = a[i].ms1 = (s[l]==1);
        a[i].cover = s[l];
        a[i].sum = s[l];
        return;
    }
    int mid = (l+r)>>1;
    init(lc);
    init(rc);
    pushup(i);
}

void insert(int l,int r,int i,int flag)
{
    pushdown(i);//让子树继承父亲的特性,因为要往下更新
    if(l<=a[i].l && a[i].r<=r)
    {
        if(flag<2)
        {
            int len = a[i].r-a[i].l+1;
            a[i].cover = flag;
            a[i].ls0 = a[i].rs0 = a[i].ms0 = flag?0:len;
            a[i].ls1 = a[i].rs1 = a[i].ms1 = flag?len:0;
            a[i].sum = flag?len:0;
        }
        else
        {
            a[i].x_or = 1;
            XOR(i);
        }
    }
    else
    {
        if(l<=a[lson].r)
            insert(l,r,lson,flag);
        if(r>=a[rson].l)
            insert(l,r,rson,flag);
        pushup(i);
    }
}

int query(int l,int r,int i,int flag)
{
    pushdown(i);
    if(l<=a[i].l && a[i].r<=r)
    {
        if(flag == 3) return a[i].sum;
        else return a[i].ms1;
    }
    else
    {
        if(r<=a[lson].r) return query(l,r,lson,flag);
        if(l>=a[rson].l) return query(l,r,rson,flag);
        if(flag == 3)
        return query(l,a[lson].r,lson,flag)+query(a[rson].l,r,rson,flag);
        int ans1 = min(a[lson].rs1,a[lson].r-l+1)+min(a[rson].ls1,r-a[rson].l+1);
        int ans2 = max(query(l,a[lson].r,lson,flag),query(a[rson].l,r,rson,flag));
        return max(ans1,ans2);
    }
}

int main()
{
    int t,l,r,flag;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i = 1;i<=n;i++)
        scanf("%d",&s[i]);
        init(1,n,1);
        while(m--)
        {
            scanf("%d%d%d",&flag,&l,&r);
            l++;
            r++;
            if(flag<3)
            insert(l,r,1,flag);
            else
            printf("%d\n",query(l,r,1,flag));
        }
    }

    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值