HDU 3397 Sequence operation

花了一秒钟时间构思,写了好几天。弱。

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;

const int maxn=100000+10;
int T,N,Q,ans;
struct SegTree
{
    int zero;//零的个数
    int one;//一的个数
    int lsum;//从左边开始的最长连续的1的长度
    int rsum;//从右边开始的最长连续的1的长度
    int msum;//这段区间连续最长的1的长度

    int Lsum;//从左边开始的最长连续的0的长度
    int Rsum;//从右边开始的最长连续的0的长度
    int Msum;//这段区间连续最长的0的长度

    int f;

}segTree[maxn*4];

void tra1(int rt,int len)//变0
{
    segTree[rt].zero=len;
    segTree[rt].one=0;
    segTree[rt].lsum=0;
    segTree[rt].rsum=0;
    segTree[rt].msum=0;
    segTree[rt].Lsum=len;
    segTree[rt].Rsum=len;
    segTree[rt].Msum=len;
}

void tra2(int rt,int len)//变1
{
    segTree[rt].zero=0;
    segTree[rt].one=len;
    segTree[rt].lsum=len;
    segTree[rt].rsum=len;
    segTree[rt].msum=len;
    segTree[rt].Lsum=0;
    segTree[rt].Rsum=0;
    segTree[rt].Msum=0;
}

void Swap(int rt)
{
    swap(segTree[rt].zero,segTree[rt].one);
    swap(segTree[rt].lsum,segTree[rt].Lsum);
    swap(segTree[rt].rsum,segTree[rt].Rsum);
    swap(segTree[rt].msum,segTree[rt].Msum);
}

void pushUp(int rt,int len)
{
    //确定零的个数
    segTree[rt].zero=segTree[2*rt].zero+segTree[2*rt+1].zero;

    //确定一的个数
    segTree[rt].one=segTree[2*rt].one+segTree[2*rt+1].one;

    //确定从左边开始最长连续1的长度
    if(segTree[2*rt].msum==len-len/2)
        segTree[rt].lsum=segTree[2*rt].lsum+segTree[2*rt+1].lsum;
    else
        segTree[rt].lsum=segTree[2*rt].lsum;

    //确定从右边开始最长连续1的长度
    if(segTree[2*rt+1].rsum==len/2)
        segTree[rt].rsum=segTree[2*rt].rsum+segTree[2*rt+1].rsum;
    else
        segTree[rt].rsum=segTree[2*rt+1].rsum;

    //确定这段区间连续最长的1的长度
    segTree[rt].msum=max(segTree[2*rt].msum,segTree[2*rt+1].msum);
    segTree[rt].msum=max(segTree[rt].msum,segTree[2*rt].rsum+segTree[2*rt+1].lsum);

    //确定从左边开始最长连续0的长度
    if(segTree[2*rt].Msum==len-len/2)
        segTree[rt].Lsum=segTree[2*rt].Lsum+segTree[2*rt+1].Lsum;
    else
        segTree[rt].Lsum=segTree[2*rt].Lsum;

    //确定从右边开始最长连续0的长度
    if(segTree[2*rt+1].Rsum==len/2)
        segTree[rt].Rsum=segTree[2*rt].Rsum+segTree[2*rt+1].Rsum;
    else
        segTree[rt].Rsum=segTree[2*rt+1].Rsum;

    //确定这段区间连续最长的0的长度
    segTree[rt].Msum=max(segTree[2*rt].Msum,segTree[2*rt+1].Msum);
    segTree[rt].Msum=max(segTree[rt].Msum,segTree[2*rt].Rsum+segTree[2*rt+1].Lsum);

}

void pushDown(int rt,int len)
{
    if(segTree[rt].f==0)
    {
        segTree[2*rt].f=segTree[2*rt+1].f=0;

        tra1(2*rt,len-len/2);
        tra1(2*rt+1,len/2);
    }

    else if(segTree[rt].f==1)
    {
        segTree[2*rt].f=segTree[2*rt+1].f=1;

        tra2(2*rt,len-len/2);
        tra2(2*rt+1,len/2);
    }

    else
    {
        Swap(2*rt);
        if(segTree[2*rt].f==0) segTree[2*rt].f=1;
        else if(segTree[2*rt].f==1) segTree[2*rt].f=0;
        else if(segTree[2*rt].f==-1) segTree[2*rt].f=2;
        else segTree[2*rt].f=-1;

        Swap(2*rt+1);
        if(segTree[2*rt+1].f==0) segTree[2*rt+1].f=1;
        else if(segTree[2*rt+1].f==1) segTree[2*rt+1].f=0;
        else if(segTree[2*rt+1].f==-1) segTree[2*rt+1].f=2;
        else segTree[2*rt+1].f=-1;
    }
    segTree[rt].f=-1;
}

void build(int l,int r,int rt)
{
    segTree[rt].f=-1;

    if(l==r)
    {
        int x;
        scanf("%d",&x);
        if(x==0) tra1(rt,1);
        else if(x==1) tra2(rt,1);
        return;
    }

    int m=(l+r)/2;
    build(l,m,2*rt);
    build(m+1,r,2*rt+1);

    pushUp(rt,r-l+1);
}

void update(int L,int R,int f,int Xor,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        if(f==-1)//第二种操作
        {
            Swap(rt);
            if(segTree[rt].f==1) segTree[rt].f=0;
            else if(segTree[rt].f==0) segTree[rt].f=1;
            else if(segTree[rt].f==-1)  segTree[rt].f=2;
            else segTree[rt].f=-1;
        }

        else //第零种,第一种操作
        {
            if(f==0) tra1(rt,r-l+1);
            else tra2(rt,r-l+1);
            segTree[rt].f=f;
        }
        return;
    }

    if(segTree[rt].f!=-1)
        pushDown(rt,r-l+1);

    int m=(l+r)/2;
    if(L<=m) update(L,R,f,Xor,l,m,2*rt);
    if(R>m) update(L,R,f,Xor,m+1,r,2*rt+1);

    pushUp(rt,r-l+1);
}

int quary1(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
        return segTree[rt].one;

    if(segTree[rt].f!=-1)
        pushDown(rt,r-l+1);

    int m=(l+r)/2;
    int res=0;
    if(L<=m) res+=quary1(L,R,l,m,2*rt);
    if(R>m) res+=quary1(L,R,m+1,r,2*rt+1);
    pushUp(rt,r-l+1);
    return res;
}

int quary2(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r) return segTree[rt].msum;
    if(segTree[rt].f!=-1) pushDown(rt,r-l+1);

    int m=(l+r)/2;
    if(R<=m) return quary2(L,R,l,m,2*rt);
    else if(L>m) return quary2(L,R,m+1,r,2*rt+1);
    else
    {
        int Q1=quary2(L,R,l,m,2*rt);
        int Q2=quary2(L,R,m+1,r,2*rt+1);

        int E=max(Q1,Q2);

        int Min1=min(segTree[2*rt].rsum,m-L+1);
        int Min2=min(segTree[2*rt+1].lsum,R-m);

        E=max(E,Min1+Min2);
        return E;
    }
    pushUp(rt,r-l+1);
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&N,&Q);
        build(1,N,1);
        for(int i=1;i<=Q;i++)
        {
            int op,a,b;
            scanf("%d%d%d",&op,&a,&b);
            a++;b++;

            if(op==0) update(a,b,0,-1,1,N,1);
            if(op==1) update(a,b,1,-1,1,N,1);
            if(op==2) update(a,b,-1,1,1,N,1);
            if(op==3) printf("%d\n", quary1(a,b,1,N,1));
            if(op==4) printf("%d\n",quary2(a,b,1,N,1));
        }
    }
    return 0;
}
时间: 2024-10-14 22:44:57

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 区间合并

操作 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,

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

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(线段树&#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(线段树多操作,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 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. 从

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 题意: 给你一串01串,有5种操作 0. 区间全部变为0 1.区间全部变为1 2.区间异或 3.询问区间1的个数 4.询问区间被最长连续1的长度 思路: 这5个操作都是比较基础的线段树操作,难点在于有两种修改操作,这类题之前也写过,之前是乘法和加法,这个是区间亦或和区间更新值,但是思路是可以借鉴的,我们要推出这两个操作的关系,这样才能维护好这两个标记,我们用两个标记:same , rev ,分别表