zoukankan      html  css  js  c++  java
  • 线段树 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;
    }

    敲之甚急 代码凌乱 请见谅

  • 相关阅读:
    Codeforces Round #321 (Div. 2) D. Kefa and Dishes 状压dp
    Codeforces Round #406 (Div. 2) D. Legacy 线段树建模+最短路
    HDU 4897 Little Devil I 树链剖分+线段树
    HDU 5405 Sometimes Naive 树链剖分+bit*****
    HDU 5274 Dylans loves tree 树链剖分+线段树
    BZOJ 2243: [SDOI2011]染色 树链剖分+线段树区间合并
    HDU 5544 Ba Gua Zhen dfs+高斯消元
    HDU 3949 XOR 线性基
    BZOJ 2460: [BeiJing2011]元素 线性基
    Educational Codeforces Round 18 C. Divide by Three DP
  • 原文地址:https://www.cnblogs.com/akioi/p/12215200.html
Copyright © 2011-2022 走看看