Longest Subarray

题目传送门

解题思路

本题求一个最大的子区间,满足区间内的数字要么出现次数大于等于k次,要么没出现过。给定区间内的数字范围是1~c。

如果r为右边界,对于一种数字x,满足条件的左边界l的范围是r左边第一个x出现的位置+1(即这段区间内没有出现过x,如果x在1r内都没有出现过,那么1r自然都是l的合法范围),以及1到从右往左数数第k个x出现的位置(即这段区间内的x出现次数大于等于k)。所以我们只要找到同时是c种数字的合法左边界的位置中最小的,然后枚举所有的i作为右边界即可得出答案。

但是这样直接写肯定超时。所以我们用线段树来维护每个位置可以作为多少种数字的合法范围,以及一个区间内的最大值。在查询的时候只要尽量往左子树找就可以了。还有一个问题,难道我们要每次枚举都重新划分范围么?肯定是不行的。所以我们记录所有数字出现的位置,然后先让n为右边界,用线段树维护好其合法范围,再让右边界往左移,每次移动其实只是把旧的右边界归0,然后改变了旧的右边界上的数字的合法范围。我们已经记录了数字的出现位置,利用这个,只需要在线段树上进行几次修改即可,因为当左边界比右边界小的时候会得到负数,不会使答案更新,所以不归零也不会影响答案。

代码如下

#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll; inline int read(){
int res = 0, w = 0; char ch = 0;
while(!isdigit(ch)){
w |= ch == '-', ch = getchar();
}
while(isdigit(ch)){
res = (res << 3) + (res << 1) + (ch ^ 48);
ch = getchar();
}
return w ? -res : res;
} const int N = 100005; struct T{
int l, r;
int maxx, lazy;
}tree[N<<2];
int a[N];
vector<int> vec[N]; void build(int k, int l, int r)
{
tree[k].l = l;
tree[k].r = r;
tree[k].lazy = tree[k].maxx = 0;
if(l == r)
return;
int mid = (l + r) / 2;
build(2*k, l, mid);
build(2*k+1, mid + 1, r);
} inline void push_down(int k)
{
if(tree[k].lazy){
tree[2*k].maxx += tree[k].lazy;
tree[2*k+1].maxx += tree[k].lazy;
tree[2*k].lazy += tree[k].lazy;
tree[2*k+1].lazy += tree[k].lazy; //+=
tree[k].lazy = 0;
}
} void insert(int k, int l, int r, int u)
{
if(l > r)
return;
if(tree[k].l >= l && tree[k].r <= r){
tree[k].lazy += u;
tree[k].maxx += u;
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
push_down(k);
if(l <= mid)
insert(2*k, l, r, u);
if(r > mid)
insert(2*k+1, l, r, u);
tree[k].maxx = max(tree[2*k].maxx, tree[2*k+1].maxx);
} int n, c, k; int query(int k)
{
if(tree[k].maxx < c)
return n + 1;
if(tree[k].l == tree[k].r)
return tree[k].l;
push_down(k);
if(tree[2*k].maxx == c)
return query(2*k);
else
return query(2*k+1);
} int main()
{
while(scanf("%d%d%d", &n, &c, &k) != EOF){
for(int i = 1; i <= n; i ++)
a[i] = read();
for(int i = 1; i <= n; i ++)
vec[a[i]].push_back(i);
build(1, 1, n);
for(int i = 1; i <= c; i ++){
if(vec[i].empty())
insert(1, 1, n, 1);
else {
insert(1, vec[i][vec[i].size() - 1] + 1, n, 1);
if(vec[i].size() >= k)
insert(1, 1, vec[i][vec[i].size() - k], 1);
}
}
int ans = 0;
for(int i = n; i >= 1; i --){
ans = max(ans, i - query(1) + 1);
if(vec[a[i]].size() >= k)
insert(1, 1, vec[a[i]][vec[a[i]].size() - k], -1);
vec[a[i]].pop_back();
if(vec[a[i]].empty())
insert(1, 1, i, 1);
else {
insert(1, vec[a[i]][vec[a[i]].size() - 1] + 1, i - 1, 1);
if(vec[a[i]].size() >= k)
insert(1, 1, vec[a[i]][vec[a[i]].size() - k], 1);
}
}
printf("%d\n", ans);
}
return 0;
}

2019杭电多校第二场hdu6602 Longest Subarray(线段树)的更多相关文章

  1. [2019杭电多校第二场][hdu6602]Longest Subarray(线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6602 题目大意为求最长的区间,满足C种数字在区间内要么不出现,要么出现的次数都不小于K. 大致的分析一 ...

  2. 2019杭电多校第二场hdu6601 Keen On Everything But Triangle

    Keen On Everything But Triangle 题目传送门 解题思路 利用主席树求区间第k小,先求区间内最大的值,再求第二大,第三大--直到找到连续的三个数可以构成一个三角形.因为对于 ...

  3. [2019杭电多校第二场][hdu6601]Keen On Everything But Triangle

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6601 题意是说用给定区间内的数字组成周长最大的三角形. 大致做法就是求区间第1大,第2大和第3大然后判 ...

  4. [2019杭电多校第二场][hdu6599]I Love Palindrome String(回文自动机&&hash)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6599 题目大意为求字符串S有多少个子串S[l,r]满足回文串的定义,并且S[l,(l+r)/2]也满足 ...

  5. [2019杭电多校第二场][hdu6598]Harmonious Army(最小割)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6598 题意是说一个军队有n人,你可以给他们每个人安排战士或者法师的职业,有m对人有组合技,组合技的信息 ...

  6. 2019牛客多校第二场E MAZE(线段树 + 矩阵)题解

    题意: n * m的矩阵,为0表示可以走,1不可以走.规定每走一步只能向下.向左.向右走.现给定两种操作: 一.1 x y表示翻转坐标(x,y)的0.1. 二.2 x y表示从(1,x)走到(n,y) ...

  7. 2018 Multi-University Training Contest 2 杭电多校第二场

    开始逐渐习惯被多校虐orz  菜是原罪 1004  Game    (hdoj 6312) 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6312 虽然披着 ...

  8. 2019年杭电多校第二场 1012题Longest Subarray(HDU6602+线段树)

    题目链接 传送门 题意 要你找一个最长的区间使得区间内每一个数出现次数都大于等于\(K\). 思路 我们通过固定右端点考虑每个左端点的情况. 首先对于每个位置,我们用线段树来维护它作为\(C\)种元素 ...

  9. 2019年杭电多校第二场 1008题Harmonious Army(HDU6598+最小割+建图)

    题目链接 传送门 题意 有\(n\)个士兵,要你给他们分配职业.有\(m\)对关系,对于某一对关系\(u,v\),如果同为勇士则总能力增加\(a\),同法师则增加\(c\),一个勇士一个法师增加\(\ ...

随机推荐

  1. python trojan development 2nd —— use python to send mail and listen to the key board then combine them

    请勿用于非法用途!!!!!本人概不负责!!!原创作品,转载说明出处!!!!! from pynput.keyboard import Key,Listener import logging impor ...

  2. 浅入深出Vue:数据绑定

    上一篇我们使用了简单的数据渲染,那么如果说我们想要动态渲染标签的 class 可以这么操作么? 为什么绑定 简单的数据渲染,包括表达式.函数在内.其实都只是在标签中渲染,如果遇到以下情况怎么办呢: 需 ...

  3. java源码解析之String类(五)

    /* * 切片函数,非常重要,这里一定要牢记beginIndex是开始位置,endIndex是结束位置,区别于以前学的offset是开始位置,而count或length是个数和长度 * 比如说,new ...

  4. 初步接触 Java Net 网络编程

    本文目的是大概了解 Java 网络编程体系,需要一点点 Java IO 基础,推荐教程 系统学习 Java IO.主要参考 JavaDoc 和 Jakob Jenkov 的英文教程<Java N ...

  5. 【设计模式】行为型08状态模式(status Pattern)

    状态模式(status Pattern)       定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类.其别名为状态对象(Objects for States).与命令模式 ...

  6. yii后台模板标签

    yii模板中的label标签 <?php echo $form->labelEx($model,'name'); ?> 编译后: <label for="Projec ...

  7. jmeter分析性能报告时的误区

    概述 我们用jmeter做性能测试,必然需要学会分析测试报告.但是初学者常常因为对概念的不清晰,最后被测试报告带到沟里去. 常见的误区 分析响应时间全用平均值 响应时间不和吞吐量挂钩 响应时间和吞吐量 ...

  8. HDU 1007:Quoit Design(分治求最近点对)

    http://acm.hdu.edu.cn/showproblem.php?pid=1007 题意:平面上有n个点,问最近的两个点之间的距离的一半是多少. 思路:用分治做.把整体分为左右两个部分,那么 ...

  9. HDU 5763:Another Meaning(字符串匹配)

    http://acm.hdu.edu.cn/showproblem.php?pid=5763 Another Meaning Problem Description   As is known to ...

  10. SpringBoot第二十一篇:整合ActiveMQ

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11190048.html 版权声明:本文为博主原创文章,转载请附上博文链接! 引言   前一章节中 ...