HDU-4521 小明系列问题――小明序列(线段树)

题目大意:求LIS,但是要求LIS中相邻的两个元素之间的距离要大于d。

题目分析:线段树。节点(l,r)保存信息为LIS的最后一个元素落在[l,r]之间的最大长度。从第d+2个元素开始查询更新操作,但要在更新第i-d+1个元素信息之后。

代码如下:

# include<iostream>
# include<cstdio>
# include<queue>
# include<vector>
# include<list>
# include<cstring>
# include<algorithm>
using namespace std;

const int N=100000;

int dp[N+5];
int val[N+5];
int tr[N*4+5];

void build(int rt,int l,int r)
{
	tr[rt]=0;
	if(l!=r){
		int mid=l+(r-l)/2;
		build(rt<<1,l,mid);
		build(rt<<1|1,mid+1,r);
	}
}

void update(int rt,int l,int r,int p,int v)
{
	if(l==r)
		tr[rt]=max(tr[rt],v);
	else{
		int mid=l+(r-l)/2;
		if(p<=mid) update(rt<<1,l,mid,p,v);
		else update(rt<<1|1,mid+1,r,p,v);
		tr[rt]=max(tr[rt<<1],tr[rt<<1|1]);
	}
}

int query(int rt,int l,int r,int L,int R)
{
	if(L<=l&&r<=R)
		return tr[rt];
	int mid=l+(r-l)/2;
	if(R<=mid) return query(rt<<1,l,mid,L,R);
	if(L>mid) return query(rt<<1|1,mid+1,r,L,R);
	return max(query(rt<<1,l,mid,l,mid),query(rt<<1|1,mid+1,r,mid+1,R));
}

int main()
{
	int n,d;
	while(~scanf("%d%d",&n,&d))
	{
		int ans=1;
		build(1,0,N);
		for(int i=0;i<n;++i){
			scanf("%d",val+i);
			if(i>=d+1)
				update(1,0,N,val[i-d-1],dp[i-d-1]);
			if(val[i]>0)
				dp[i]=query(1,0,N,0,val[i]-1)+1;
			else dp[i]=1;
			ans=max(ans,dp[i]);
			
		}
		printf("%d
",ans);
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/20143605--pcx/p/5510096.html