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. 「玩转树莓派」树莓派 3B+ 配置无线WiFi

    前言 网线不方便还花钱,有自带的无线 WiFi 模块为啥不用. 网络模式 这里我们先介绍两种网络模式,WPA-Personal 与 WPA-Enterprise. WPA-Personal 大多数家庭 ...

  2. java finally块执行时机分析

    java里 finally 关键字通常与try catch块一起使用.用来在方法结束前或发生异常时做一些资源释放的操作.最近也看到网上有一些讨论try catch finally关键词执行的顺序的文章 ...

  3. Requests方法 -- cookie绕过验证码登录操作

    前言有些登录的接口会有验证码:短信验证码,图形验证码等,这种登录的话验证码参数可以从后台获取的(或者查数据库最直接).获取不到也没关系,可以通过添加 cookie 的方式绕过验证码. 1.这里以登录博 ...

  4. ES6_09_Generator函数

    Generator函数: 概念: 1.ES6提供的解决异步编程的方案之一 2.Generator函数是一个状态机,内部封装了不同状态的数据, 3.用来生成遍历器对象 4.可暂停函数(惰性求值), yi ...

  5. 巧妙解决element-ui下拉框选项过多的问题

    1. 场景描述 不知道你有没有这样的经历,下拉框的选项很多,上万个选项甚至更多,这个时候如果全部把数据放到下拉框中渲染出来,浏览器会卡死,体验会特别不好 用人会说element-ui的select有一 ...

  6. Go - Map 集合

    目录 概述 声明 Map 生成 JSON 编辑和删除 推荐阅读 概述 Map 集合是无序的 key-value 数据结构. Map 集合中的 key / value 可以是任意类型,但所有的 key ...

  7. Gym 101257B:2Trees(DFS+思维)

    http://codeforces.com/gym/101257/problem/B 题意:给出两棵叶子数一样的树,在将叶子合并之后,对这个图进行染色,相邻的结点颜色不能相同,问最少需要染的颜色数,并 ...

  8. 按行读取String类型

    BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(content.getByt ...

  9. kuangbin专题 专题一 简单搜索 Fire Game FZU - 2150

    题目链接:https://vjudge.net/problem/FZU-2150 题意:’ . '代表火无法烧着的地方,‘ # ’表示草,火可以烧着.选择任意两个‘ # ’(可以两个都选同一个 ‘ # ...

  10. 7.秋招复习简单整理之请你讲讲 Statement 和 PreparedStatement 的区别?哪个性能更好?

    Statement和PreparedStatement都是数据库用于执行SQL语句的句柄,但是PreparedStatement代表一个预编译的SQL. 以下是PreparedStatement和St ...