2019HDU多校第二场——HDU6602 Longest Subarray【线段树】

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Problem Description

You are given two integers C,K and an array of N integers a1,a2,...,aN. It is guaranteed that the value of ai is between 1 to C.

We define that a continuous subsequence al,al+1,...,ar(l≤r) of array a is a good subarray if and only if the following condition is met:

∀x∈[1,C],∑i=lr[ai=x]=0or∑i=lr[ai=x]≥K

It implies that if a number appears in the subarray, it will appear no less than K times.

You should find the longest good subarray and output its length. Or you should print 0 if you cannot find any.

Input

There are multiple test cases.

Each case starts with a line containing three positive integers N,C,K(N,C,K≤105).

The second line contains N integer a1,a2,...,aN(1≤ai≤C).

We guarantee that the sum of Ns, the sum of Cs and the sum of Ks in all test cases are all no larger than 5×105.

 

Output

For each test case, output one line containing an integer denoting the length of the longest good subarray. 

 

Sample Input

7 4 2

2 1 4 1 4 3 2

Sample Output

Source

2019 Multi-University Training Contest 2

题意:

给你n个数,最大值为C,要求区间出现的每个数的次数到不小于k,求满足条件的最长区间的长度

分析:

(官方题解是这么说的)

如果右端点固定,对于每种元素,可行的左端点下标是两段连续的区间。对于每种元素,将它的可行左端点区间在线段树中加一。当右端点右移的时候,维护C种元素的可行左端点。 查询时只需要询问线段树中最小的、值为C的下标即可。

简单点说就是当右端点变为此时的i时(加上当前这个点),维护可行和不可行的左端点,找出可行左端点的最小值并更新答案。(有简单的注释)

#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
using namespace std;
const int maxn=404040;
vector<int> g[101010];
int n,C,k;
int lazy[maxn],tree[maxn],pos[maxn];
void sum(int rt,int x)
{
	tree[rt]+=x;lazy[rt]+=x;
}
void build(int l,int r,int rt)
{
	tree[rt]=lazy[rt]=0;pos[rt]=l;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(l,mid,lson);build(mid+1,r,rson);
}
void up(int rt)
{
	tree[rt]=max(tree[lson],tree[rson]);
	pos[rt]=((tree[rt]==tree[lson])?pos[lson]:pos[rson]);
}
void down(int rt)
{
	if(!lazy[rt]) return;
	sum(lson,lazy[rt]);sum(rson,lazy[rt]);
	lazy[rt]=0;
}
void update(int ql,int qr,int x,int l,int r,int rt)
{
	if(ql>qr) return;
	if(ql<=l && r<=qr) {sum(rt,x);return;}
	int mid=(l+r)>>1;
	down(rt);
	if(ql<=mid) update(ql,qr,x,l,mid,lson);
	if(qr>mid) update(ql,qr,x,mid+1,r,rson);
	up(rt);
}
int query(int ql,int qr,int l,int r,int rt)
{
	if(tree[rt]!=C) return 0;
	if(ql<=l && r<=qr) return pos[rt];
	int mid=(l+r)>>1;
	down(rt);
	if(ql<=mid) 
	{
		int t=query(ql,qr,l,mid,lson);
		if(t) return t;
	}
	if(qr>mid) return query(ql,qr,mid+1,r,rson);
	return 0;
}
int main()
{
	while (~scanf("%d%d%d",&n,&C,&k))
	{
		for (int i=1;i<=C;i++) g[i].clear(),g[i].pb(0);
		int ans=0;
		build(1,n,1);
		for (int i=1;i<=n;i++)
		{
			int x;scanf("%d",&x);
			update(i,i,C-1,1,n,1);
			update(g[x].back()+1,i-1,-1,1,n,1);//加了当前点后这个区间不可行
			g[x].pb(i);
			int tmp=(int)g[x].size()-k-1;
			if(tmp>=0) update(g[x][tmp]+1,g[x][tmp+1],1,1,n,1);//加了当前点后这个区间可行
			int res=query(1,i,1,n,1);//可行位置的最小值
			if(!res) continue;
			ans=max(ans,i-res+1);//长度
		}
		printf("%d\n",ans);
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值