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 ,分别表示区间更新值和区间异或,那么向下更新的时候如果如果有same标记,清空当前区间的rev标记,简单维护下就好了,如果有rev标记,且有same标记,那么直接对same异或维护,如果没有same标记那么就维护下区间异或就好了。

写的超爽,一遍就a了,美滋滋,还以为又要找好久的错。。

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid int m = (l + r) >> 1
#define ll long long

const int M = 1e5 + 10;
int lsum1[M<<2],rsum1[M<<2],sum1[M<<2];
int lsum0[M<<2],rsum0[M<<2],sum0[M<<2];
int sum[M<<2],same[M<<2],rev[M<<2];
int a[M];

void pushup(int l,int r,int rt){
    mid;
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    lsum0[rt] = lsum0[rt<<1]; lsum1[rt] = lsum1[rt<<1];
    rsum0[rt] = rsum0[rt<<1|1]; rsum1[rt] = rsum1[rt<<1|1];
    if(lsum0[rt] == m-l+1) lsum0[rt] += lsum0[rt<<1|1];
    if(rsum0[rt] == r-m) rsum0[rt] += rsum0[rt<<1];
    if(lsum1[rt] == m-l+1) lsum1[rt] += lsum1[rt<<1|1];
    if(rsum1[rt] == r-m) rsum1[rt] += rsum1[rt<<1];
    sum0[rt] = max(max(sum0[rt<<1],sum0[rt<<1|1]),lsum0[rt<<1|1]+rsum0[rt<<1]);
    sum1[rt] = max(max(sum1[rt<<1],sum1[rt<<1|1]),lsum1[rt<<1|1]+rsum1[rt<<1]);
}

void swa(int len,int rt){
    sum[rt] = len - sum[rt];
    swap(lsum1[rt],lsum0[rt]);
    swap(rsum1[rt],rsum0[rt]);
    swap(sum1[rt],sum0[rt]);
}

void pushdown(int l,int r,int rt){
    mid;
    if(same[rt]!=-1){
        rev[rt<<1] = rev[rt<<1|1] = 0;
        same[rt<<1] = same[rt<<1|1] = same[rt];
        if(same[rt]){
            sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = m-l+1;
            sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = r-m;
            lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = 0;
        }
        else{
            sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = 0;
            sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = 0;
            lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = m-l+1;
            sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = r-m;
        }
        same[rt] = -1;
    }
    if(rev[rt]){
        if(same[rt<<1] != -1){
            same[rt<<1] ^= 1;
            if(same[rt<<1]){
                sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = m-l+1;
                lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = 0;
            }
            else{
                sum[rt<<1] = lsum1[rt<<1] = rsum1[rt<<1] = sum1[rt<<1] = 0;
                lsum0[rt<<1] = rsum0[rt<<1] = sum0[rt<<1] = m-l+1;
            }
        }
        else{
            rev[rt<<1] ^= 1;
            swa(m-l+1,rt<<1);
        }
        if(same[rt<<1|1] != -1){
            same[rt<<1|1] ^= 1;
            if(same[rt<<1|1]){
                sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = r-m;
                sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = 0;
            }
            else{
                sum[rt<<1|1] = lsum1[rt<<1|1] = rsum1[rt<<1|1] = sum1[rt<<1|1] = 0;
                sum0[rt<<1|1] = rsum0[rt<<1|1] = lsum0[rt<<1|1] = r-m;
            }
        }
        else{
            rev[rt<<1|1] ^= 1;
            swa(r-m,rt<<1|1);
        }
        rev[rt] = 0;
    }
}

void build(int l,int r,int rt){
    same[rt] = -1; rev[rt] = 0;
    lsum1[rt] = rsum1[rt] = lsum0[rt] = rsum0[rt] = sum0[rt] = sum1[rt] = sum[rt] = 0;
    if(l == r){
        if(a[l]){
            lsum1[rt] = sum[rt] = sum1[rt] = rsum1[rt] = 1;
            lsum0[rt] = rsum0[rt] = sum0[rt] = 0;
        }
        else {
            sum1[rt] = sum[rt] = sum1[rt] = rsum1[rt] = 0;
            lsum0[rt] = rsum0[rt] = sum0[rt] = 1;
        }
        return ;
    }
    mid ;
    build(lson); build(rson);
    pushup(l,r,rt);
}

void update_same(int L,int R,int c,int l,int r,int rt){
    if(L <= l&&R >= r){
        rev[rt] = 0;
        same[rt] = c;
        if(same[rt]){
            sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = r-l+1;
            lsum0[rt] = rsum0[rt] = sum0[rt] = 0;
        }
        else{
            sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = 0;
            lsum0[rt] = rsum0[rt] = sum0[rt] = r-l+1;
        }
        return ;
    }
    pushdown(l,r,rt);
    mid;
    if(L <= m) update_same(L,R,c,lson);
    if(R > m) update_same(L,R,c,rson);
    pushup(l,r,rt);
}

void update_rev(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        if(same[rt] != -1){
            same[rt] ^= 1;
            if(same[rt]){
                sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = r-l+1;
                lsum0[rt] = rsum0[rt] = sum0[rt] = 0;
            }
            else{
                sum[rt] = lsum1[rt] = rsum1[rt] = sum1[rt] = 0;
                lsum0[rt] = rsum0[rt] = sum0[rt] = r-l+1;
            }
        }
        else{
            rev[rt] ^= 1;
            swa(r-l+1,rt);
        }
        return ;
    }
    mid ;
    pushdown(l,r,rt);
    if(L <= m) update_rev(L,R,lson);
    if(R > m) update_rev(L,R,rson);
    pushup(l,r,rt);
}

int query_sum(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        return sum[rt];
    }
    pushdown(l,r,rt);
    mid;
    int ret = 0;
    if(L <= m) ret += query_sum(L,R,lson);
    if(R > m) ret += query_sum(L,R,rson);
    return ret;
}

int query_max(int L,int R,int l,int r,int rt){
    if(L <= l&&R >= r){
        return sum1[rt];
    }
    pushdown(l,r,rt);
    mid;
    int ret = 0;
    if(L > m) return query_max(L,R,rson);
    if(R <= m) return query_max(L,R,lson);
    int t1 = query_max(L,R,lson);
    int t2 = query_max(L,R,rson);
    int ls = min(rsum1[rt<<1],m-L+1);
    int rs = min(lsum1[rt<<1|1],R-m);
    return max(max(t1,t2),ls+rs);
}

int main()
{
    int n,q,x,y,op,t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&q);
        for(int i = 1;i <= n;i ++)
            scanf("%d",&a[i]);
        build(1,n,1);
        while(q--){
            scanf("%d%d%d",&op,&x,&y);
            x++; y++;
            if(op == 0){
                update_same(x,y,0,1,n,1);
            }
            else if(op == 1){
                update_same(x,y,1,1,n,1);
            }
            else if(op == 2){
                update_rev(x,y,1,n,1);
            }
            else if(op == 3){
                printf("%d\n",query_sum(x,y,1,n,1));
            }
            else {
                printf("%d\n",query_max(x,y,1,n,1));
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/kls123/p/9781070.html

时间: 2024-11-17 18:26:04

hdu 3397 Sequence operation (线段树 区间合并 多重标记)的相关文章

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

线段树大杂烩~ 各种操作都有,细心点不难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(线段树多操作,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 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability

HDU 5316——Magician——————【线段树区间合并区间最值】

Magician Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1613    Accepted Submission(s): 470 Problem Description Fantasy magicians usually gain their ability through one of three usual methods:

HDU - 3308 - LCIS (线段树 - 区间合并)

题目传送:LCIS 线段树,区间合并,一次过啦,没有纠结,这几天过的最愉快的一个题 思路:求最长连续上升子序列,外带单点更新,经典的线段树题目.具体看代码注释 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack>

HDU 1540 POJ 2892 线段树区间合并

给出N个点,M次操作,N个点开始在一条线上链式相连 D操作  把某点删除掉 Q操作  询问某点一共可以连接多少个点 R操作  把上一次删除的点还原 线段树处理区间合并 分别记录每个区间的左端连续最长和右端连续最长 #include "stdio.h" #include "string.h" struct node { int l,r,lx,rx,x; }data[200010]; int mark[50100]; int Max(int a,int b) { if

HDU 1540 Tunnel Warfare(线段树 区间合并 最大连续区间)

题意  有n个连在一起的地道  接下来有m个操作  D x 炸掉x号地道  炸掉后x所在的区间就不连续了  Q x 查询输出包括x的最大连续区间长度   R修复最后一个被炸的地道  注意输入R时可能并没有需要修复的地道 线段树的区间合并问题  线段树要维护3个信息 len  对应区间的最大连续长度 ll  对应区间最左端的一段连续长度 lr  对应区间最右端的一段连续长度 那么双亲节点的这些信息和孩子节点有什么关系呢  容易发现 双亲的len 是 左孩子的len 右孩子的len  左孩子的右端长