码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-07-25 20:28:15      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:using   pre   线段   维护   杭电多校   font   fine   void   can   

大意: 给定序列$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);
	}
}

 

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

标签:using   pre   线段   维护   杭电多校   font   fine   void   can   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!