HDU3397 Sequence operation(线段树的区间合并)

Sequence operation

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7547    Accepted Submission(s): 2254


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
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   1698  1540  2871  1255  3333 
题意:
0 a b 把[a,b]内的数都改成0
1 a b 把[a,b]内的数都改成1
2 a b [a,b]内1改为0,0改为1

3 a b 输出[a,b]内1的个数
4 a b 输出[a,b]内1的连续序列最长长度。

思路:
对于0和1的个数统计应该不难,线段树的基本操作,求区间和。
对于区间合并
举例数字1,处理区间内1的最长连续序列长度。
每个区间应该记录包含左端点最长连续序列长度lmax, 包含右端点最长连续序列长度rmax, 整个区间的最长连续序列长度max。
向上更新的时候,一个区间的lmax等于它左儿子的lmax,如果lmax刚好等于左儿子的整个区间,就加上右儿子的lmax,;
同理这个区间的rmax等于它右儿子的rmax,如果rmax刚好等于右儿子的整个区间,就要加上左儿子的rmax。
一个区间的max等于左儿子max, 右儿子max,还有中间那部分(左儿子rmax+右儿子的lmax)三者间最大的值。
这样就可以处理区间内最长的连续序列长度。

updata的时候要整段更新,由于向下更新可能会出现多个标记叠在一起未被处理,也就是修改同一个区间多次后又访问它的儿子区间。
0操作后进行1操作其实相当进行1操作,1操作后进行2操作相当于进行0操作,类似地可以用一个数组表示操作之间的转换,使得标记一直都只是一种操作,这样向下更新可以一次处理。

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lson rt<<1
#define rson rt<<1|1
#define maxn 200010
using namespace std;
struct node{
    int left, right;
    int num0, num1, zmx, omx;
    int zlx, zrx, olx, orx;
    int dis(){return right-left+1;}
}t[maxn<<2];
int par[3][3];
int add[maxn<<2];
void pushUp(int rt){
    t[rt].zlx = t[lson].zlx + (t[lson].zlx==t[lson].dis()?t[rson].zlx:0);
    t[rt].zrx = t[rson].zrx + (t[rson].zrx==t[rson].dis()?t[lson].zrx:0);

    t[rt].olx = t[lson].olx + (t[lson].olx==t[lson].dis()?t[rson].olx:0);
    t[rt].orx = t[rson].orx + (t[rson].orx==t[rson].dis()?t[lson].orx:0);

    t[rt].num0 = t[lson].num0 + t[rson].num0;
    t[rt].num1 = t[lson].num1 + t[rson].num1;

    t[rt].zmx = max(max(t[lson].zmx, t[rson].zmx), t[lson].zrx+t[rson].zlx);
    t[rt].omx = max(max(t[lson].omx, t[rson].omx), t[lson].orx+t[rson].olx);
}
int x;
void build(int rt, int l, int r){
    t[rt].left = l;
    t[rt].right = r;
    add[rt] = -1;
    if(l == r){
        scanf("%d", &x);
        if(x == 0){
            t[rt].num0 = t[rt].zmx = t[rt].zlx = t[rt].zrx = 1;
            t[rt].num1 = t[rt].omx = t[rt].olx = t[rt].orx = 0;
        }else{
            t[rt].num0 = t[rt].zmx = t[rt].zlx = t[rt].zrx = 0;
            t[rt].num1 = t[rt].omx = t[rt].olx = t[rt].orx = 1;
        }
        return;
    }
    int mid = (l+r)>>1;
    build(lson, l, mid);
    build(rson, mid+1, r);
    pushUp(rt);
}
void change0(int rt){
    t[rt].num0 = t[rt].zmx = t[rt].zlx = t[rt].zrx = t[rt].dis();
    t[rt].num1 = t[rt].omx = t[rt].olx = t[rt].orx = 0;
}
void change1(int rt){
    t[rt].num0 = t[rt].zmx = t[rt].zlx = t[rt].zrx = 0;
    t[rt].num1 = t[rt].omx = t[rt].olx = t[rt].orx = t[rt].dis();
}
void change2(int rt){
    swap(t[rt].num0, t[rt].num1);
    swap(t[rt].zmx, t[rt].omx);
    swap(t[rt].zlx, t[rt].olx);
    swap(t[rt].zrx, t[rt].orx);
}
void Par(int fa, int son){
    if(add[son] == -1) add[son] = add[fa];
    else add[son] = par[add[son]][add[fa]];
}
void pushDown(int rt){
    if(add[rt] != -1){
        Par(rt, lson);
        Par(rt, rson);
        if(add[rt] == 0){
            change0(lson);
            change0(rson);
        }else if(add[rt] == 1){
            change1(lson);
            change1(rson);
        }else if(add[rt] == 2){
            change2(lson);
            change2(rson);
        }
        add[rt] = -1;
    }
}
void updata(int rt, int l, int r, int op){
    pushDown(rt);
    if(l==t[rt].left&&t[rt].right==r){
        if(add[rt] == -1) add[rt] = op;
        else add[rt] = par[add[rt]][op];
        if(add[rt] == 0) change0(rt);
        else if(add[rt] == 1) change1(rt);
        else if(add[rt] == 2) change2(rt);
        return;
    }
    int mid = (t[rt].left+t[rt].right)>>1;
    if(r<=mid) updata(lson, l, r, op);
    else if(mid<l) updata(rson, l, r, op);
    else{
        updata(lson, l, mid, op);
        updata(rson, mid+1, r, op);
    }
    pushUp(rt);
}
int query(int rt, int l, int r, int ask){
    pushDown(rt);
    if(l==t[rt].left&&t[rt].right==r){
        if(ask == 3) return t[rt].num1;
        else return t[rt].omx;
    }
    int mid = (t[rt].left+t[rt].right)>>1;
    if(r<=mid) return query(lson, l, r, ask);
    else if(l>mid) return query(rson, l, r, ask);
    else{
        int ltmp = query(lson, l, mid, ask);
        int rtmp = query(rson, mid+1, r, ask);
        int sum = 0;
        sum = min(t[lson].orx, mid-l+1) + min(t[rson].olx, r-mid);
        if(ask == 4) return max(max(ltmp, rtmp), sum);//求1连续
        else return (ltmp+rtmp);//求1个数
    }
}
int main()
{
    int T, i, n, m, op, c, d;
    par[0][0] = 0, par[0][1] = 1, par[0][2] = 1;
    par[2][2] = -1, par[2][0] = 0, par[2][1] = 1;
    par[1][1] = 1, par[1][0] = 0, par[1][2] = 0;
    scanf("%d", &T);
    while(T--){
        scanf("%d %d", &n, &m);
        build(1, 1, n);
        while(m--){
            scanf("%d %d %d", &op, &c, &d);
            if(op<3) updata(1, c+1, d+1, op);
            else printf("%d\n", query(1, c+1, d+1, op));
        }
    }

}
/*
1
10 10
0 0 0 1 0 1 0 1 1 1
1 0 9
2 0 9
2 0 5
4 0 9
*/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值