首页 > 其他 > 详细

[BZOJ 1858] 序列操作(真·线段树大模板)

时间:2018-08-24 10:27:16      阅读:137      评论:0      收藏:0      [点我收藏+]

·题目描述

lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:

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

对于每一种询问操作,lxhgww都需要给出回答,聪明的程序员们,你们能帮助他吗?(不能啊w(?Д?)w!!!)

·输入格式

输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目。

第二行包括n个数,表示序列的初始状态 接下来m行,每行3个数,op,a,b,(0≤op≤4,0≤a≤b)

·输出格式

对于每一个询问操作,输出一行,包括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

·样例输出

5
2
6
5

·数据范围

对于30%的数据,1≤n,m≤1000
对于100%的数据,1≤n,m≤100000

题解:

不得不说,这道题真的是烦。一看见这道题就想到曾经数次打超长程序无限调试的经历Σ(っ °Д °;)っ。果不其然,这次的程序再一次刷新了我OI生涯中的最长程序纪录。

不多说了,这题就是对每个节点记录几个信息:\(LSum[x]\)为从左端点开始的最长的\(0\)\(1\)个数,\(RSum[x]\)同理,而\(Sum[x]\)是该节点所代表的区间内\(0\)\(1\)的和,\(len[x]\)就代表了这个区间内连续多少个\(0\)\(1\)

再考虑修改操作,对于操作\(3\),我们可以记录一个\(cover\)值,代表这个节点是否被\(0\)\(1\)覆盖,然后在标记下传的时候进行维护。而对于操作\(4\),我们则是选择再次记录一个\(rev\)值,表示这个区间进行多少次翻转,翻转\(2\)次可以视为不翻转。

PS:我做这题+调试达到快5小时,我实在是蒟蒻啊。。。。。。

贴代码

#include <ctype.h>
#include <stdio.h>
#include <iostream>
#define Re register int
using namespace std;

struct SegmentTree{
    int cover,rev,len[2],Sum[2];
    int LSum[2],RSum[2];
}T[500005];
int N,M,A[100005],opt,a,b;

inline int read()
{
    int x=0,w=0; char ch=0;
    while (!isdigit(ch)) w|=ch=='-',ch=getchar();
    while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
inline int max(int a,int b) {return a>b?a:b;}
inline int min(int a,int b) {return a<b?a:b;}
inline void swap(int &a,int &b) {a^=b; b^=a; a^=b;}
void PushUp(int id,int l,int r,int mid)
{
    int ls=id*2,rs=id*2+1;
    for (int i=0; i<2; ++i)
    {
        T[id].LSum[i]=(T[ls].LSum[i]==mid-l+1)?
            T[ls].LSum[i]+T[rs].LSum[i]:T[ls].LSum[i];
        T[id].RSum[i]=(T[rs].RSum[i]==r-mid)?
            T[rs].RSum[i]+T[ls].RSum[i]:T[rs].RSum[i];
        T[id].len[i]=max(T[ls].RSum[i]+T[rs].LSum[i],
            max(T[ls].len[i],T[rs].len[i]));
        T[id].Sum[i]=T[ls].Sum[i]+T[rs].Sum[i];
    }
}
inline void PushDown(int id,int l,int r,int mid)
{
    if (!T[id].rev&&T[id].cover==-1) return;
    if (l!=r)
    for (int son=id*2; son<=id*2+1; ++son)
    {
        if (T[id].cover!=-1)
        {
            T[son].cover=T[id].cover; T[son].rev=0; T[son].Sum[T[id].cover^1]=0;
            T[son].Sum[T[id].cover]=(son==id*2)?mid-l+1:r-mid;
            T[son].len[T[id].cover]=T[son].LSum[T[id].cover]=T[son].RSum[T[id].cover]=(son==id*2)?mid-l+1:r-mid;
            T[son].len[T[id].cover^1]=T[son].LSum[T[id].cover^1]=T[son].RSum[T[id].cover^1]=0;
        }
        if (T[id].rev)
        {
            T[son].rev^=T[id].rev;
            swap(T[son].len[0],T[son].len[1]);
            swap(T[son].LSum[0],T[son].LSum[1]);
            swap(T[son].RSum[0],T[son].RSum[1]);
            swap(T[son].Sum[0],T[son].Sum[1]);
        }
    }
    T[id].rev=0; T[id].cover=-1;
}
void Build(int id,int l,int r)
{
    if (l==r)
    {
        T[id].cover=-1; T[id].rev=0; T[id].Sum[A[l]]=1;
        T[id].len[A[l]]=1; T[id].LSum[A[l]]=T[id].RSum[A[l]]=1;
        return;
    }
    int mid=(l+r)>>1; T[id].cover=-1;
    Build(id*2,l,mid); Build(id*2+1,mid+1,r);
    PushUp(id,l,r,mid);
}
void Modify(int id,int l,int r,int L,int R,int c)
{
    if (L<=l&&r<=R)
    {
        T[id].cover=c; T[id].rev=0;
        T[id].Sum[c]=r-l+1; T[id].Sum[c^1]=0;
        T[id].len[c]=r-l+1; T[id].len[c^1]=0;
        T[id].LSum[c]=r-l+1; T[id].LSum[c^1]=0;
        T[id].RSum[c]=r-l+1; T[id].RSum[c^1]=0;
        return;
    }
    int mid=(l+r)>>1; PushDown(id,l,r,mid);
    if (L<=mid) Modify(id*2,l,mid,L,R,c);
    if (mid<R) Modify(id*2+1,mid+1,r,L,R,c);
    PushUp(id,l,r,mid);
}
void Reverse(int id,int l,int r,int L,int R)
{
    if (L<=l&&r<=R)
    {
        T[id].rev^=1;
        swap(T[id].Sum[0],T[id].Sum[1]);
        swap(T[id].len[0],T[id].len[1]);
        swap(T[id].LSum[0],T[id].LSum[1]);
        swap(T[id].RSum[0],T[id].RSum[1]);
        return;
    }
    int mid=(l+r)>>1; PushDown(id,l,r,mid);
    if (L<=mid) Reverse(id*2,l,mid,L,R);
    if (mid<R) Reverse(id*2+1,mid+1,r,L,R);
    PushUp(id,l,r,mid);
}
int QuerySum(int id,int l,int r,int L,int R)
{
    if (L<=l&&r<=R) return T[id].Sum[1];
    int mid=(l+r)>>1,ret=0; PushDown(id,l,r,mid);
    if (L<=mid) ret+=QuerySum(id*2,l,mid,L,R);
    if (mid<R) ret+=QuerySum(id*2+1,mid+1,r,L,R);
    return ret;
}
int QueryLen(int id,int l,int r,int L,int R)
{
    if (L<=l&&r<=R) return T[id].len[1];
    int mid=(l+r)>>1,ret=0; PushDown(id,l,r,mid);
    if (L<=mid) ret=max(ret,QueryLen(id*2,l,mid,L,R));
    if (mid<R) ret=max(ret,QueryLen(id*2+1,mid+1,r,L,R));
    return max(ret,min(mid-L+1,T[id*2].RSum[1])+min(R-mid,T[id*2+1].LSum[1]));
}
int main(int argc, char const *argv[])
{
    N=read(),M=read();
    for (Re i=1; i<=N; ++i) A[i]=read();
    Build(1,1,N);
    for (Re i=1; i<=M; ++i)
    {
        opt=read(),a=read()+1,b=read()+1;
        switch (opt)
        {
            case 0:case 1:Modify(1,1,N,a,b,opt); break;
            case 2: Reverse(1,1,N,a,b); break;
            case 3: printf("%d\n",QuerySum(1,1,N,a,b)); break;
            case 4: printf("%d\n",QueryLen(1,1,N,a,b)); break;
        }
    }
    return 0;
}

[BZOJ 1858] 序列操作(真·线段树大模板)

原文:https://www.cnblogs.com/Alkri/p/9527543.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!