• 线段树 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;
    }

    敲之甚急 代码凌乱 请见谅

  • 相关阅读:
    毕业设计:专业填写格式
    关于《毕业设计指导记录》的建议
    毕业设计通知
    毕业设计答辩:幻灯片内容制作要点
    Latex 模版生成会议论文 不显示Keywords,而是显示 Index Terms- ,改成Keywords 方法
    mysql information_schema
    C# odbc
    cwRsync 配置文件详解
    Rsync
    openssl rsa 私钥 PKCS8私钥 公钥
  • 原文地址:https://www.cnblogs.com/akioi/p/12215200.html
Copyright © 2020-2023  润新知