P2253 好一个一中腰鼓!

P2253 好一个一中腰鼓!

本蒟蒻第一次用线段树做连续最长子段



线段树是将一个大区间二分成两个小区间,通过递归解决两个小区间的问题,然后合并。得到大区间的解。

类比一下分治法求单个最长连续子段。

每次也都是将一个大区间分成两个小区间。分别解决完小区间后。将小区间合并,从分界点左右遍历。暴力的求连续子序列的长度。

然后将两个小区间分别作为一个区间求解的最优值和从分界点的连续子段长度比较,然后就得到了这个大区间的最长连续子段的长度。

可是,如果在线段树中呢?每次从分界点暴力的求时间复杂度太高。

那能不能预处理出来呢?

答案是肯定的。

我们可以如此想像。对于一次区间。他的最长连续子段能在什么位置呢?

无非就是在左右端点处开始或结束,或者是在区间内部(就是在最长连续子段中有可能没有左右节点)。我们只需要记录这三个值。

在递归合并时求从分界点的连续子段时只需要用从左区间以右端点结尾的连续子段接上右区间以左端点开始的连续子段就可以了。

至于可以接在一起的条件是什么。会在代码中讲解



那什么时候结束呢?也就是递归到了叶子节点(只有一个元素)。

所以我们先定义叶子的状态。

全是1.(左边开始的连续子段的长度,右边结束的连续子段的长度,在,在区间内部的连续子段的长度)

然后更改一个点后,处理他的父节点。如此边回溯边维护就可以了

#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
    }
}

原文地址:https://www.cnblogs.com/Lance1ot/p/8671881.html

时间: 2024-10-15 02:22:32

P2253 好一个一中腰鼓!的相关文章

洛谷 P2253 好一个一中腰鼓 --线段树

P2253 好一个一中腰鼓 --线段树 题目背景 话说我大一中的运动会就要来了,据本班同学剧透(其实早就知道了),我萌萌的初二年将要表演腰鼓[喷],这个无厘头的题目便由此而来. Ivan乱入:“忽一人大呼:‘好一个安塞腰鼓!’满座寂然,无敢哗者,遂与外人间隔.” 题目描述 设想一下,腰鼓有两面,一面是红色的,一面是白色的.初二的苏大学神想给你这个oier出一道题.假设一共有N(1<=N<=20,000)个同学表演,表演刚开始每一个鼓都是红色面朝向观众,舞蹈老师会发出M(1<=M<=

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

传送门 不得不说 这真是一道不错的线段树的题目 这一道题的大意就是说 一开始所有的状态均为0 会有m次指令 每一次可以把一个点的状态进行更改 原来是0就变成1 原来是1就变成0 为了锻炼代码能力 我决定还是中规中矩地写线段树 这一道题还规定了一种串  就是0和1间隔交替 (比如010101  101 01010) 你每一次更改之后 要求出所有的点组成的序列中最长的连续“01”串 那么这一道题如果用线段树来做 转移会稍微复杂一点 我们定义sum为当前区间最长的01串 lsum为当前区间最长的前缀0

洛谷 P2253 好一个一中腰鼓!

题目背景 话说我大一中的运动会就要来了,据本班同学剧透(其实早就知道了),我萌萌的初二年将要表演腰鼓[喷],这个无厘头的题目便由此而来. Ivan乱入:“忽一人大呼:‘好一个安塞腰鼓!’满座寂然,无敢哗者,遂与外人间隔.” 题目描述 设想一下,腰鼓有两面,一面是红色的,一面是白色的.初二的苏大学神想给你这个oier出一道题.假设一共有N(1<=N<=20,000)个同学表演,表演刚开始每一个鼓都是红色面朝向观众,舞蹈老师会发出M(1<=M<=20,000)个指令,如果指令发给第i个

洛谷P2253 好一个一中腰鼓!

题目背景 话说我大一中的运动会就要来了,据本班同学剧透(其实早就知道了),我萌萌的初二年将要表演腰鼓[喷],这个无厘头的题目便由此而来. Ivan乱入:"忽一人大呼:'好一个安塞腰鼓!'满座寂然,无敢哗者,遂与外人间隔." 题目描述 设想一下,腰鼓有两面,一面是红色的,一面是白色的.初二的苏大学神想给你这个oier出一道题.假设一共有N(1<=N<=20,000)个同学表演,表演刚开始每一个鼓都是红色面朝向观众,舞蹈老师会发出M(1<=M<=20,000)个指令

【P2253】 好一个一中腰鼓!

Description 给定一个01子串和操作数,每次操作可以使一个元素0变为1, 1变为0,求区间最长连续相邻不相等的长度 Solution 对于最长连续不相等,我们可以用几个量来维护,为: 1  lf 从左边开始的最长连续相邻不相等最大长度 2 rf 从右边开始的最长连续相邻不相等最大长度 3 mf 内部的最长连续相邻不相等最大长度 所以,最长的长度为max(tr[1].lf, tr[1].rf, tr[1].mf),对于每一个变量我们可以这样维护 tr[x].lf = max(tr[x <

浴谷夏令营题单

这是群里一位神犇整理的,我只负责将它们做完. 一.暴力.搜索Luogu 1588 丢失的牛Luogu 1463 [SDOI2005]反素数antBzoj 1085 [SCOI2005]骑士精神Luogu 1019 单词接龙Luogu 1078 文化之旅Luogu 1312 Mayan游戏Luogu 3823 蚯蚓排队Codeforces 444B Codeforces 555DLuogu 1979 华容道 二.初等数论Poj 3292 H合成数Luogu 1890 gcd区间Luogu 1029

[HNOI2018]爆零记

Day 0 完全不知道做什么. 打了一个splay板子,还没调出来emmmmm 不想做题目,最后做的一题是[HNOI2016]的超(sha)难(bi)题网络. 当我希望省选能出一下树剖时,旁边的大佬跟我说,树剖太简单了,不会出qwqQAQ. 然后下午见到了ylx(redbag)大佬,%%%%%%果然是个巨佬,还长的挺好看的 请巨佬yzk和巨佬ylx吃了顿饭,问题是最后还掉了100,穷了qwq ylx巨佬奶了一口网络流 我奶了字符串,yzk奶了线性基 然而最后好像都没考????(反正我没看出来)

通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统?

1 从文件操作角度分析. 文件的概念以及文件类型指针 在c语言中,文件被看成是由一个一个的字符或字节组成的.根据数据的组织形式,文件可分为文本文件和二进制文件两种. 文本文件又被称为ASCII文件,文本文件在磁盘中存放时每个字符对应一个字节,用于放其对应的ASCII码.文本文件可在屏幕上按字符显示. 二进制文件时将数据转换成二进制形式然后存储起来的文件.二进制文件虽然也可在屏幕上显示,但其内容无法读懂. 文件指针是一中结构体类型变量,c编译系统已将结构定义好,并命名为FILE,我们直接用定义就好

洛谷——P2256 一中校运会之百米跑

P2256 一中校运会之百米跑 题目背景 在一大堆秀恩爱的**之中,来不及秀恩爱的苏大学神踏着坚定(?)的步伐走向了100米跑的起点.这时苏大学神发现,百米赛跑的参赛同学实在是太多了,连体育老师也忙不过来.这时体育老师发现了身为体育委员的苏大学神,便来找他帮忙.可是苏大学神需要热身,不然跑到一半就会抽(筋).于是他就找到了你...如果你帮助体育老师解决了问题,老师就会给你5个积分. 题目描述 假设一共有N(2<=N<=20000)个参赛选手.(尼玛全校学生都没这么多吧) 老师会告诉你这N个选手