2019杭电多校二 L Longest Subarray (线段树)

大意: 给定序列$a$, 元素范围$[1,C]$, 求一个最长子序列, 满足每个元素要么不出现, 要么出现次数$\le K$.

枚举右端点, 考虑左端点合法的位置. 显然一定是$C$种颜色合法位置的并, 可以用线段树维护合法颜色的种类数, 每次二分出最小的满足合法个数为$C$的位置更新答案.

考虑右端点移动到$i$, 存在一个位置$p$, 满足

对于颜色$a_i$的合法区间为$[1,p]$, 不合法区间为$[p+1,i]$.

可以求出上一次计算的$a_i$合法位置的增量与不合法位置的增量, 用线段树区间加减即可.

类似题目可以做一下[POI2015]KIN, 也是对每种颜色维护一个增量.

#include <iostream>
#include <cstdio>
#include <queue>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define hr puts("")
using namespace std;
const int N = 1e6+10;
int n, c, k, a[N];
vector<int> v[N];
struct _ {
	int ma,tag,pos;
	void upd(int x) {ma+=x,tag+=x;}
	_ operator + (const _ &rhs) const {
		_ ret;
		ret.ma = max(ma, rhs.ma);
		ret.pos = ret.ma==ma?pos:rhs.pos;
		ret.tag = 0;
		return ret;
	}
} tr[N<<2];
void build(int o, int l, int r) {
	tr[o].ma=c,tr[o].tag=0,tr[o].pos=l;
	if (l!=r) build(ls),build(rs);
}
void pd(int o) {
	if (tr[o].tag) {
		tr[lc].upd(tr[o].tag);
		tr[rc].upd(tr[o].tag);
		tr[o].tag=0;
	}
}
void add(int o, int l, int r, int ql, int qr, int v) {
	if (l>qr||r<ql) return;
	if (ql<=l&&r<=qr) return tr[o].upd(v);
	pd(o),add(ls,ql,qr,v),add(rs,ql,qr,v),tr[o]=tr[lc]+tr[rc];
}
int qry(int o, int l, int r, int ql, int qr) {
	if (l>qr||r<ql||tr[o].ma!=c) return 0;
	if (ql<=l&&r<=qr) return tr[o].pos;
	pd(o);
	int t = qry(ls,ql,qr);
	return t?t:qry(rs,ql,qr);
}
int main() {
	while (~scanf("%d%d%d",&n,&c,&k)) {
		REP(i,1,n) scanf("%d",a+i);
		REP(i,1,c) v[i].clear(),v[i].pb(0);
		int ans = 0;
		build(1,1,n);
		REP(i,1,n) {
			if (v[a[i]].back()+1<=i) add(1,1,n,v[a[i]].back()+1,i,-1);
			v[a[i]].pb(i);
			int p = v[a[i]].size()-k-1;
			if (p>=0) add(1,1,n,v[a[i]][p]+1,v[a[i]][p+1],1);
			int j = qry(1,1,n,1,i);
			if (j) ans = max(ans, i-j+1);
		}
		printf("%d\n",ans);
	}
}

原文地址:https://www.cnblogs.com/uid001/p/11242982.html

时间: 2024-10-23 06:16:04

2019杭电多校二 L Longest Subarray (线段树)的相关文章

2019杭电多校二 F. Fantastic Magic Cube (FWT)

大意: 给定$N^3$立方体, 每个单位立方体权值为三个坐标异或, 每次沿坐标轴切一刀, 得分为两半内权值和的乘积, 求切成$n^3$块的最大得分. 可以发现得分与切法无关, 假设每个点权值为$a_i$, 就有$ans=\frac{(\sum a_i)^2-\sum a_i^2}{2}$. 从而转化为求$f_x=\sum\limits_{i=0}^{N-1}\sum\limits_{j=0}^{N-1}\sum\limits_{k=0}^{N-1}[(i\oplus j\oplus k)=x]$

2019杭电多校第九场

2019杭电多校第九场 熟悉的后半场挂机节奏,又苟进首页了,很快乐 1001. Rikka with Quicksort upsolved 不是我做的,1e9调和级数分段打表 1002. Rikka with Cake solved at 01:11 有一个矩形,给你很多射线(射线只有横平竖直的四个方向),问把矩形切成了多少块 队友说答案是交点数加一,作为一个合格的工具人,当然是把队友的想法实现啦 二维坐标离散化枚举纵坐标维护横坐标,常规套路,树状数组也可以做(我是线段树写习惯了根本没想起来还有

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

Longest Subarray 题目传送门 解题思路 本题求一个最大的子区间,满足区间内的数字要么出现次数大于等于k次,要么没出现过.给定区间内的数字范围是1~c. 如果r为右边界,对于一种数字x,满足条件的左边界l的范围是r左边第一个x出现的位置+1(即这段区间内没有出现过x,如果x在1~r内都没有出现过,那么1~r自然都是l的合法范围),以及1到从右往左数数第k个x出现的位置(即这段区间内的x出现次数大于等于k).所以我们只要找到同时是c种数字的合法左边界的位置中最小的,然后枚举所有的i作

2019 杭电多校 第五场

2019 Multi-University Training Contest 5 补题链接:2019 Multi-University Training Contest 5 罚时爆炸 自闭场 1004 equation (HDU 6627) 题意: 给定一个整数 \(C\) 和 \(N\) 组 \(a_i,b_i\),求 \(∑_{i=1}^N|a_i\cdot x + b_i| = C\) 的所有解,如果有无穷多个解就输出 -1. 思路 分类讨论 分类讨论去绝对值.根据 \(b_i / a_i

2019杭电多校第三场 1004 Distribution of books

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6606 考虑二分答案,我们二分一个值\(x\),那么要怎么来验证这个答案是否可行,考虑dp求解,设\(dp[i]\)为前i个在答案为\(x\)的情况下划分最最多组数,那么若\(dp[n] \geq k\) 则这个x可行, 很显然可以看出\(x\)是单调的,所以二分. \[dp[i] = max(dp[j]) + 1 (sum[i] - sum[j-1] \leq x)\] 如果直接采用暴力枚举的话复杂

2019杭电多校第三次hdu6609 Find the answer(线段树)

Find the answer 题目传送门 解题思路 要想变0的个数最少,显然是优先把大的变成0.所以离散化,建立一颗权值线段树,维护区间和与区间元素数量,假设至少减去k才能满足条件,查询大于等于k的最少数量即可. 代码如下 #include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; inline int read(){ int res = 0, w = 0; char c

2019杭电多校第六场hdu6638 Snowy Smile(线段树+枚举)

Snowy Smile 题目传送门 解题思路 先把y离散化,然后把点按照x的大小进行排序,我们枚举每一种x作为上边界,然后再枚举其对应的每一种下边界.按照这种顺序插入点,这是一个压维的操作,即在线段树中的y位置加上其w,并利用线段树来更新动态的最大子段和. 代码如下 #include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; const int N = 2005; stru

2019杭电多校&amp;CCPC网络赛&amp;大一总结

多校结束了, 网络赛结束了.发现自己还是太菜了,多校基本就是爆零和签到徘徊,第一次打这种高强度的比赛, 全英文,知识点又很广,充分暴露了自己菜的事实,发现数学还是很重要的.还是要多刷题,少玩游戏. 网络赛也打的不好, 开场写01,先是思路错,再是没考虑特判,直接罚时爆炸,再是写06,题意又看错,看了很久.其中队友过07, 我看08,队友03,08先乱写了个优先队列直接t,然后边吃边想,想到正解,忘记加换行... 最后看02, 也没写出来,队友03也是没调出来, 口上说着主攻数据结构,连想的算法都

2019 杭电多校 第八场

2019 Multi-University Training Contest 8 补题链接:2019 Multi-University Training Contest 8 1003 Acesrc and Good Numbers HDU 6659 题意 定义 \(f(d, n)\) 为十进制下 \(1\) 到 \(n\) 所有数的数位中数字 \(d\) 出现的次数.给定 \(x\),找出最大的 \(n(n \le x)\) 满足 \(f(d, n) = n\). 题解 看到了一个神仙做法. 显