线段树 P2253 好一个一中腰鼓!

Posted 空山新雨后blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树 P2253 好一个一中腰鼓!相关的知识,希望对你有一定的参考价值。

传送门

不得不说 这真是一道不错的线段树的题目

这一道题的大意就是说

一开始所有的状态均为0

会有m次指令

每一次可以把一个点的状态进行更改

原来是0就变成1

原来是1就变成0

 

为了锻炼代码能力 我决定还是中规中矩地写线段树

这一道题还规定了一种串  就是0和1间隔交替 (比如010101  101 01010)

你每一次更改之后 要求出所有的点组成的序列中最长的连续“01”串  

 

 

那么这一道题如果用线段树来做 转移会稍微复杂一点

我们定义sum为当前区间最长的01串

lsum为当前区间最长的前缀01串

rsum为当前区间最长的后缀01串

 

那我们怎么进行转移呢

 

先说sum

sum可以是左区间的sum、右区间sum的最大值

也可以是左区间的右半部分(后缀)和右区间的左半部分(前缀)  这两个01串拼起来

当然 这也有一定的条件 必须左半部分的最后一个字符与右半区间的第一个字符是不相同的 拼接起来之后才合法

 

然后lsum怎么转移?

首先肯定可以是左半区间的lsum转移过来

但是还有一种情况

就是如果左半区间整个都是合法的01串(也就是左半区间的前缀长度 就等于 整个左半区间的长度)

那么和起来之后最长的前缀01串有可能是整个左半区间+右半区间的前缀串  

同样 这也有一定的条件 就是必须左半区间的最后一个字符等于右半区间的第一个字符

 

rsum则与lsum同理

有可能是右半区间的rsum转移过来

也有可能是整个右半区间+左半区间的后缀

条件与lsum的类似

 

这样子我们就非常完美地建出了一棵线段树

 

这样子我们的解法其实更加高级

题目可以随便询问任何一个区间 我都可以非常自信地回答出该区间内合法的01串的长度

 

接下来就上我的宏伟代码啦

(其实我也非常惊讶为什么我10分钟就做出来了。。一遍AC。。)

 

//P2253 好一个一中腰鼓!
#include<bits/stdc++.h>
#define maxn 20005
using namespace std;
int Color[maxn];
struct node{
    int l,r,sum,lsum,rsum;
}t[maxn<<2];
void build(int p,int l,int r)
{
    t[p].l=l;t[p].r=r;
    if(l==r)
    {
        t[p].sum=t[p].lsum=t[p].rsum=1;
        return;
    }
    int mid=l+r>>1;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
    t[p].sum=max(t[p*2].sum,t[p*2+1].sum);
    if(Color[t[p*2].r]!=Color[t[p*2+1].l]) t[p].sum=max(t[p].sum,t[p*2].rsum+t[p*2+1].lsum);
    t[p].lsum=t[p*2].lsum;
    if(t[p*2].lsum==(t[p*2].r-t[p*2].l+1)&&Color[t[p*2].r]!=Color[t[p*2+1].l])
        t[p].lsum=max(t[p].lsum,t[p*2].r-t[p*2].l+1+t[p*2+1].lsum);
    t[p].rsum=t[p*2+1].rsum;
    if(t[p*2+1].rsum==(t[p*2+1].r-t[p*2+1].l+1)&&Color[t[p*2].r]!=Color[t[p*2+1].l])
        t[p].rsum=max(t[p].rsum,t[p*2+1].r-t[p*2+1].l+1+t[p*2].rsum);
    return;
}
void Change(int p,int l,int r,int Ind)
{
    if(l==Ind&&r==Ind)
    {
        Color[Ind]=1-Color[Ind];
        return;        
    }
    int mid=l+r>>1;
    if(Ind>mid)
        Change(p*2+1,mid+1,r,Ind);
    else Change(p*2,l,mid,Ind);
    t[p].sum=max(t[p*2].sum,t[p*2+1].sum);
    if(Color[t[p*2].r]!=Color[t[p*2+1].l]) t[p].sum=max(t[p].sum,t[p*2].rsum+t[p*2+1].lsum);
    t[p].lsum=t[p*2].lsum;
    if(t[p*2].lsum==(t[p*2].r-t[p*2].l+1)&&Color[t[p*2].r]!=Color[t[p*2+1].l])
        t[p].lsum=max(t[p].lsum,t[p*2].r-t[p*2].l+1+t[p*2+1].lsum);
    t[p].rsum=t[p*2+1].rsum;
    if(t[p*2+1].rsum==(t[p*2+1].r-t[p*2+1].l+1)&&Color[t[p*2].r]!=Color[t[p*2+1].l])
        t[p].rsum=max(t[p].rsum,t[p*2+1].r-t[p*2+1].l+1+t[p*2].rsum);
    
}
void Ask(){
    printf("%d
",t[1].sum);
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    build(1,1,n);
    while(m--)
    {
        int Index;
        scanf("%d",&Index);
        Change(1,1,n,Index);
        Ask();
    }
    return 0;
}

 

敲之甚急 代码凌乱 请见谅

技术图片

以上是关于线段树 P2253 好一个一中腰鼓!的主要内容,如果未能解决你的问题,请参考以下文章

P2253 好一个一中腰鼓!

P2253 好一个一中腰鼓!

P2253 好一个一中腰鼓!

P2253 好一个一中腰鼓!

洛谷 P2253 好一个一中腰鼓!

洛谷P2253 好一个一中腰鼓!