hdu3397Sequence operation--线段树

hdu3397Sequence 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)


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

思路:比较难做的就是异或操作……首先用一个mx数组表示区间内的最长连续“1”的个数,但需要进行区间合并,因此就需要用lx表示包括该区间最左边是“1”的最长的连续个数,用rx表示该区间内最右边是“1”的最长连续个数,,这样也方便跟新mx……还有一个比较麻烦的就是在进行操作2时,,若不用延迟标记肯定是不行的,,但怎么用呢,似乎不好用……哈哈,,用color数组表示该区间内的数字是不是统一的,若是直接更新就好了,,若不是则一直往下找,,直到找到有color标记的或是直接到叶子……这也算是一个小技巧吧。。。。说到这里又想起来多校的一个题目(第八场1008 HDU 5828 Rikka with Sequence,,也是用了大概差不多的技巧过了,,不过赛后大佬随便出数据就hack了……Orz,,还需要更优化,,好神奇啊)……

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <stdlib.h>

using namespace std;

#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define inf 0x3f3f3f3f

typedef long long ll;
const int maxn = 100003;
int a[maxn<<2],sum[maxn<<2],lx[maxn<<2],rx[maxn<<2],len[maxn<<2],color[maxn<<2];
int op;
void up(int rt,int dis) {
    int mid = dis>>1;
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    lx[rt] = lx[rt<<1];
    rx[rt] = rx[rt<<1|1];
    len[rt] = max(len[rt<<1],len[rt<<1|1]);
    if(lx[rt] == (dis - mid))lx[rt] += lx[rt<<1|1];
    if(rx[rt] == mid) rx[rt] += rx[rt<<1];
    len[rt] = max(len[rt],lx[rt<<1|1]+rx[rt<<1]);
    len[rt] = max(len[rt],max(lx[rt],rx[rt]));
}
void down(int rt,int dis) {
    int mid = dis>>1;
    color[rt<<1] = color[rt<<1|1] = color[rt];
    len[rt<<1] = lx[rt<<1] = rx[rt<<1] = sum[rt<<1] = (color[rt]==1?(dis-mid):0);
    len[rt<<1|1] = lx[rt<<1|1] = rx[rt<<1|1] = sum[rt<<1|1] = (color[rt]==1?mid:0);
    color[rt] = -1;
}
void build(int l,int r,int rt) {
    if(l == r) {
        scanf("%d",&a[l]);
        if(a[l])sum[rt] = len[rt] = lx[rt] = rx[rt] = 1;
        color[rt] = a[l];
        return ;
    }
    int mid = l+r>>1;
    build(lson);
    build(rson);
    up(rt,r-l+1);
}
void update(int L,int R,int l,int r,int rt) {
    if(L <= l && r <= R) {
        sum[rt] = lx[rt] = rx[rt] = len[rt] = (op == 1?(r-l+1):0);
        color[rt] = op;
        return ;
    }
    if(color[rt] != -1)down(rt,r-l+1);
    int mid = l+r>>1;
    if(L <= mid)update(L,R,lson);
    if(R > mid)update(L,R,rson);
    up(rt,r-l+1);
}
void update_XOR(int L,int R,int l,int r,int rt) {
    if(L <= l && r <= R && color[rt] != -1) {
        color[rt] ^= 1;
        sum[rt] = len[rt] = lx[rt] = rx[rt] = (color[rt]==1?(r-l+1):0);
        return;
    }
    if(color[rt] != -1) down(rt,r-l+1);
    int mid = l+r>>1;
    if(L <= mid)update_XOR(L,R,lson);
    if(R > mid)update_XOR(L,R,rson);
    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];
    }
    int mid = l+r>>1;
    if(color[rt] != -1)down(rt,r-l+1);
    int ans = 0;
    if(L <= mid)ans += query_sum(L,R,lson);
    if(R > mid)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 && color[rt] != -1) {
        return len[rt];
    }
    int mid = l+r>>1,ans = 0;
    if(color[rt] != -1)down(rt,r-l+1);
    if(R <= mid)return query_len(L,R,lson);
    else if(L > mid)return query_len(L,R,rson);
    else {
        int ans1 = 0,ans2 = 0;
        ans1 = query_len(L,mid,lson);
        ans2 = query_len(mid+1,R,rson);
        ans = min(rx[rt<<1],mid-L+1)+min(lx[rt<<1|1],R-mid);
        return max(ans,max(ans1,ans2));
    }
}
int main() {
//    freopen("data.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    int t,n,m;
    scanf("%d",&t);
    int ca = 0;
    while(t--) {
        scanf("%d%d",&n,&m);
        memset(color,-1,sizeof(color));
        memset(sum,0,sizeof(sum));
        memset(lx,0,sizeof(lx));
        memset(rx,0,sizeof(rx));
        memset(len,0,sizeof(len));
        build(0,n-1,1);
        while(m--) {
            int l,r;
            scanf("%d%d%d",&op,&l,&r);
            if(op == 0 || op == 1) {
                update(l,r,0,n-1,1);
            } else if(op == 2)update_XOR(l,r,0,n-1,1);
            else if(op == 3)printf("%d\n",query_sum(l,r,0,n-1,1));
            else printf("%d\n",query_len(l,r,0,n-1,1));
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值