西安段素

题目是我自己起的

好久之前做的了。

现在又有人讲介个东西

拿出来做做样子吧。

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
",max(t[1].lf,max(t[1].mf,t[1].rf)));//手动max
    }
}
原文地址:https://www.cnblogs.com/Lance1ot/p/9130024.html