线段树

Posted $mathcal{Lance1ot}$

tags:

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

题目是我自己起的

好久之前做的了。

现在又有人讲介个东西

拿出来做做样子吧。

P2253 好一个一中腰鼓!
然而这题数据水。所以评级也不高。

#include<iostream> 
#include<cstdio>
#include<ctime>
#include<cstdlib>
using namespace std;
struct node//线段树结构体
{
    int lf;//从左开始的连续子段长度  l:left
    int mf;//在区间内部的连续子段长度 m:mid
    int rf;//以右端点结束的连续子段的长度 r:right下同
};
node t[70100];//线段树数组
int turn[2]={1,0};//转变数组,也可以自己if
int base[70100];//记录是否被反转过,0为无,1为有
void push(int &root,int &l,int &r,int &m)
{
    int ls=root<<1;//left son
    int rs=(root<<1)|1;//right son
    t[root].lf=t[ls].lf;//大区间的左端点开始的连续子段最起码是左区间以左区间左端点开头的连续子段
    if(base[m]!=base[m+1]&&m-l+1==t[ls].lf) //如果左区间整个都是连读的
        t[root].lf+=t[rs].lf;//在将右区间的以右区间开头的连续子段长度加上,下同
    t[root].rf=t[rs].rf;//处理大区间以右端点结尾的连续子段长度
    if(base[m]!=base[m+1]&&r-m==t[rs].rf) 
        t[root].rf+=t[ls].rf;
    t[root].mf=max(t[ls].mf,t[rs].mf);//在大区间内的连续子段,这一步请类比分支
    if(base[m]!=base[m+1])//左右区间拼接
        t[root].mf=max(t[root].mf,t[ls].rf+t[rs].lf);
    return ;
}
void build(int root,int l,int r)
{
    if(l==r)//叶子节点的初状态
    {
        t[root].lf=1;
        t[root].mf=1;
        t[root].rf=1;
        return ;
    }
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build((root<<1)|1,mid+1,r);
    push(root,l,r,mid);//用他两个儿子更新自己,这里用作初始化
    return ;
}
void updata(int root,int l,int r,int a)
{
    if(l>a||r<a)
        return ;
    if(l==a&&r==a)
    {
        base[l]=turn[base[l]];
        return ;//更改
    }
    int mid=(l+r)>>1;
    updata(root<<1,l,mid,a);
    updata((root<<1)|1,mid+1,r,a);
    push(root,l,r,mid);//维护线段树
    return ;
}
int main()
{
    int n,m;//输入不解释
    scanf("%d%d",&n,&m);
    build(1,1,n);
    int a;
    for(int i=1;i<=m;i++)
    {
        scanf("%d",&a);
        updata(1,1,n,a);
        printf("%d\n",max(t[1].lf,max(t[1].mf,t[1].rf)));//手动max
    }
}

以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章

线段树

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

线段树合并

数据结构——线段树

论线段树:二

线段树