【题解】C - STEP

news/2024/10/6 20:16:42

目录
  • 题目内容
    • Description
    • Input
    • Output
    • 数据规模与约定
  • 做法一
    • 思路
    • 代码
  • 做法2
    • 思路
    • 代码

题目内容

原题:洛谷P6492

Description

给定一个长度为 \(n\) 的字符序列 \(a\),初始时序列中全部都是字符L
\(q\) 次修改,每次给定一个 \(x\),若 \(a_x\)L,则将 \(a_x\) 修改成R,否则将 \(a_x\) 修改成L
对于一个只含字符LR的字符串 \(s\),若其中不存在连续的LR,则称 \(s\) 满足要求。
每次修改后,请输出当前序列 \(a\) 中最长的满足要求的连续子串的长度。

Input

第一行有两个整数,分别表示序列的长度 \(n\) 和修改操作的次数 \(q\)
接下来 \(q\) 行,每行一个整数,表示本次修改的位置 \(x\)

Output

对于每次修改操作,输出一行一个整数表示修改 \(a\) 中最长的满足要求的子串的长度。

数据规模与约定

对于全部的测试点,保证 \(1\le n,q\le2\times 10^5\)\(1\le x\le n\)

做法一

思路

首先题目可以转化为给你一个01串,需要支持单点翻转、查找最长的01交替的串。修改很好维护,但是查询比较麻烦。对于这种查询内容不方便直接合并的题,考虑使用分块。具体地,对于每个块,维护一个全局最长串长度,以最左端为起点的最长串长度,以最右端为终点的最长串长度,最左端和最右端的值,为了方便再开一个标记该区间是否完全满足01交替的限制。修改时对其所在的块暴力重构,查询时从第一个块到最后一个块遍历,先取该区间的全局最长串长度,再考虑和前面一个串的结尾合并的长度。注意判断前后合并是否合法。复杂度 \(O(n\sqrt{n})\)

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b,c;
struct Block_Array
{#define N 200002#define M 505int cnt,len,lt[M],rt[M],be[N],num[M],lnum[M],rnum[M];bool can[M],col[N];il void build(int x)//分块{len=sqrt(x);cnt=x/len;for(ri i=1;i<=cnt;i++){lt[i]=rt[i-1]+1;rt[i]=rt[i-1]+len;}if(rt[cnt]!=x){cnt++;lt[cnt]=rt[cnt-1]+1;rt[cnt]=x;}for(ri i=1;i<=cnt;i++){for(ri j=lt[i];j<=rt[i];j++){be[j]=i;}lnum[i]=rnum[i]=num[i]=1;}}il void add(int x)//暴力重构{ri y=be[x],rn=0;col[x]^=1;can[y]=false;num[y]=1;for(ri i=lt[y];i<rt[y];i++)//查找靠左最优区间的结尾{if(col[i]==col[i+1]){rn=i-lt[y]+1;break;}}if(!rn)//如果没找到就证明该块完全合法{can[y]=true;lnum[y]=rnum[y]=num[y]=rt[y]-lt[y]+1;return;}lnum[y]=rn;for(ri i=rt[y];i>lt[y];i--)//否则继续找靠右最优区间的开头{if(col[i]==col[i-1]){rnum[y]=rt[y]-i+1;break;}}rn=0;num[y]=max(lnum[y],rnum[y]);//这一句一定要加上for(ri i=lt[y];i<rt[y];i++)//在全局继续找{rn++;if(col[i]==col[i+1]){num[y]=max(num[y],rn);rn=0;}}}il int find(){ri rn=num[1],pre=rnum[1];register bool ed=col[rt[1]];//初始化for(ri i=2;i<=cnt;i++){rn=max(rn,num[i]);//先取全局if(can[i])//分讨关于合并的情况{if(ed!=col[lt[i]]){pre+=num[i];rn=max(rn,pre);}else{pre=rt[i]-lt[i]+1;}}else{if(ed!=col[lt[i]]){pre+=lnum[i];rn=max(rn,pre);}pre=rnum[i];}ed=col[rt[i]];}return rn;}#undef N#undef M
}ba;
int main()
{scanf("%d%d",&a,&b);ba.build(a);while(b--){scanf("%d",&c);ba.add(c);printf("%d\n",ba.find());}return 0;
}

做法2

思路

从分块算法中获得启发,发现这种东西可以用类似的方法在线段树上合并。维护的东西和分块基本一致。对于叶子结点的左右值直接赋值,长度直接赋值为1。单点修改相同。向上合并时先看看左右儿子在中间的值,可不可以合并,进行分讨。大体原理和分块的找答案时的处理相同。查询时直接输出线段树根处存的答案即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b,c;
struct Segment_Tree//封装线段树
{#define N 800008int left[N],right[N],num[N],lnum[N],rnum[N];bool lid[N],rid[N],can[N];il int lft(int x)//左儿子{return x<<1;}il int iht(int x)//右儿子{return x<<1|1;}il void pushup(int x)//向上合并{lid[x]=lid[lft(x)];rid[x]=rid[iht(x)];num[x]=max(num[lft(x)],num[iht(x)]);//不要忘了这里if(rid[lft(x)]!=lid[iht(x)])//对能否合并的分讨{num[x]=max(num[x],rnum[lft(x)]+lnum[iht(x)]);if(can[lft(x)]){lnum[x]=num[lft(x)]+lnum[iht(x)];}else{lnum[x]=lnum[lft(x)];}if(can[iht(x)]){rnum[x]=num[iht(x)]+rnum[lft(x)];}else{rnum[x]=rnum[iht(x)];}can[x]=can[lft(x)]&can[iht(x)];//注意万能标记也要向上合并}else{lnum[x]=lnum[lft(x)];rnum[x]=rnum[iht(x)];can[x]=false;}}il void build(int x,int lt,int rt)//建树{left[x]=lt;right[x]=rt;if(lt==rt){num[x]=lnum[x]=rnum[x]=1;can[x]=true;return;}ri me=(lt+rt)>>1;build(lft(x),lt,me);build(iht(x),me+1,rt);pushup(x);}il void add(int x,int pl)//单点修改{if(left[x]==right[x]){lid[x]^=1;rid[x]=lid[x];return;}ri me=(left[x]+right[x])>>1;if(pl<=me){add(lft(x),pl);}else{add(iht(x),pl);}pushup(x);}il int find()//查询{return num[1];}#undef N
}st;
int main()
{scanf("%d%d",&a,&b);st.build(1,1,a);while(b--){scanf("%d",&c);st.add(1,c);printf("%d\n",st.find());}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/68429.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Codeforces Rund 977 div2 个人题解(A~E1)

Codeforces Rund 977 div2 个人题解(A,B,C1,C2,E1) Dashboard - Codeforces Round 977 (Div. 2, based on COMPFEST 16 - Final Round) - Codeforces 火车头 #define _CRT_SECURE_NO_WARNINGS 1​#include <algorithm>#include <array>#include <bitset>#inc…

ide启动多个实例

ide启动多个实例 方法一: ide 2022.X及之后 Run=> Edit Configurations=> 选中项目=> “Build and run”栏=> Modify Options=> 选中“Allow multiple instances”然后就可以run多次项目了 但是要主要改端口 方法二: 先把项目打包,然后启动多个terminal,每个…

周鸿祎:用这10条打造你的完美的商业计划书(附详细讲解)

转载:周鸿祎:用这10条打造你的完美的商业计划书(附详细讲解)_产品 (sohu.com) 江湖上流传着一篇“360大佬周鸿祎版10页商业计划书PPT”,高屋建瓴的讲述了BP制作框架,很有价值。诚然,一个形式上外观精美,具有上有吸引力的BP让人赏心悦目,但更重要的还是有实实在在的内容…

DiLiGenT光度立体数据集

本文对DiLiGenT光度立体数据集进行了详细介绍。简介 ”DiLiGenT“ 光度立体数据集,全称为 calibrated Directional Lightings, objects of General reflectance, and ‘ground Truth’ shapes (normals),即使用标定过的定向光源,对一些具有常见反射率特性的物体进行光度立体…

Pool Kings All In One

Pool Kings All In One 泳池之王 Pool Kings - Mountain Paradise / 泳池之王 - 山间天堂 Utah waterfall MountainPool Kings All In One泳池之王demosPool Kings - Mountain Paradise / 泳池之王 - 山间天堂Utah waterfall Mountainhttps://vimeo.com/233842674 https://www.…

CHT

水电费是否收到fwe】今天探索一下CTH的电脑 PEPPA PIG放映室!tm的图怎么死了

visdom可视化工具

安装visdom可视化工具 pip install visdom -i 作者:太一吾鱼水 宣言:在此记录自己学习过程中的心得体会,同时积累经验,不断提高自己! 声明:博客写的比较乱,主要是自己看的。如果能对别人有帮助当然更好,不喜勿喷! 文章未经说明均属原创,学习笔记可…

测绘地理信息赋能新质生产力

在信息化与智能化浪潮的推动下,测绘地理信息作为连接现实世界与数字空间的桥梁,正逐步成为驱动经济社会发展的新质生产力。本文旨在深入探讨测绘地理信息如何通过技术创新与应用拓展,为各行各业赋能,塑造智慧社会的新面貌。一、测绘地理信息的转型之路随着卫星定位系统(如…