2019多校第二场 HDU6602 Longest Subarray(思维,线段树区间修改维护最值)

本文介绍了一种使用线段树解决寻找满足特定条件的最长连续子序列长度的问题。通过分析序列和利用线段树进行区间维护最值,文章详细解释了如何在K大于1的情况下找到符合条件的子序列。
摘要由CSDN通过智能技术生成

链接:HDU6602 Longest Subarray

题意:

含有 长度为N的序列 a[1]、a[2]、… 、a[N](其中 1 ≤ a[i] ≤ C

连续子序列 a[L]、a[L+1]、… 、a[R], 对于 1 ~ C的任意一个数如果出现了,其 出现次数必须 ≥ K(即要求 出现次数 == 0 或 ≥ K

问满足上述条件的最长连续子序列长度为多少?(N,C,K ≤ 105)



分析:

对于任意一个右端点R,因为是连续子序列,所以要找到 最远的(下标最小的)那个符合要求的左端点L

这题的方法就是设定一个数组 t[],t的下标即表示左端点L

当R=i,t[j] = m :表示当右端点R=i时,j 是1~ C中 m个数的可行左端点L,所以只有当 t[j] = C时,j 是右端点R = i 时的可行左端点。

所以 对于序列中的数 x,若 j 是此时的可行左端点,则t[j]++,每次只需要找 j 最小的 t[j] = C即可得出最终答案。

以上就是大致思路,但是具体实现要用线段树去维护数组 t[]



当K==1,显然答案直接就是N,以下我们仅讨论K>1的情况

假设 K=3,N=15( * 表示其他数):

i 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
a * x * * x * * x * * * x * x *

x有5个位置,分别为 pos[1]=2,pos[2]=5,pos[3]=8,pos[4]=12,pos[5]=14

当R=i,a[i]=x,且这是第p个位置的x 时

① 首先 t[i] 是肯定可以作为 C-1(x自身除外)个数的左端点的,所以先令 t[i] + (C-1)

② 当x前一个数不是x时(即pos[p-1]+1 ≤ pos[p] - 1 ), pos[p-1]+1 到 pos[p] - 1 原本是x的可行左端点,但现在变得不可行
以 a[8] 为例(p=3),在 R=6和R=7时,6,7均是x的可行左端点,但当 R=8时,变得不可行。
所以令 pos[p-1]+1 到 pos[p] - 1 的t[] -1

③ 若 p ≥ K,可以发现 pos[p-K]+1 到 pos[p-K+1] 本身x不可行的左端点,但现在变为了可行
以 a[14] 为例(p=5),在 R=8~13时,6,7,8均是x的不可行左端点,但当 R=14时,变得可行。
所以 令 pos[p-K]+1 到 pos[p-K+1] 的t[] +1

线段树的话具体就是维护最大值,每次找最大值的为C的子树,左右子树最大值都是C,那就往左子树找,这样就能找到最远的可行左端点。

涉及区间修改就要用到线段树的懒标记了,具体看代码。



以下代码:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=1e5+50;
int N,C,K,a[maxn];
int t[maxn<<2],laz[maxn<<2];
void pushdown(int rt,int l,int r)
{
   
    if(laz[rt]==0)
        return;           //线段树维护的是最大值
    t[rt<<1]+=
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值