hdu 5489 Removed Interval LIS变形

50 篇文章 0 订阅
40 篇文章 0 订阅
//	hdu 5489 Removed Interval LIS变形
//
//	解题思路:
//		f[i]为以a[i]为结尾的LIS
//		g[i]为以a[i]为开头的LIS
//		对于截掉一段L而言,我们可以设将i位置前的L去除,但是
//		保留i的这样的状态.这样dp[i] = max(dp[j]) (1<=j<=i-L) + g[i]
//		再对dp[i]选出一个max就是最后的答案啦.
//		关键在于如何找到最大的dp[j].
//		我们先将高度映射到线段树上,当然需要离散化一下,对于一个a[i].
//		我们查找(1,a[i]-1)区间里面的最大的dp[j]就行了.而对于插入的话
//		插入对于一个a[i-L],我们插入f[i-L]的值.
//		这个方法的技巧就在于我们多加一个元素INF放在a[i]的末尾,这样就可以
//		保证所有连续的L的序列都考虑到了.所以正确性是肯定的.
//
//	感悟:
//
//		比赛的时候,是观摩神犇学弟一起搞出来的,用的三棵线段树.确实搞出来了
//		当时十分激动,AC的感觉十分兴奋,太爽啦!继续加油吧~~~FIGHTING!!!

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(x,a,b,c) for (int x = a; x <= b; x += c)
#define pre(x,a,b,c) for (int x = a; x >= b; x -= c)
#define cls(x,a) memset(x,a,sizeof(x))
using namespace std;
const int MAX_N = 1e5 + 8;
const int INF = 0x7f7f7f7f;
int N,L;
int a[MAX_N];
int tem[MAX_N];
int f[MAX_N];
int g[MAX_N];
int h[MAX_N];

struct IntervalTree{

#define lson(ro) (ro<<1)
#define rson(ro) (ro<<1|1)
	int maxv[MAX_N<<2];
	int ql,qr,v;


	inline void push_up(int ro){
		maxv[ro] = max(maxv[lson(ro)],maxv[rson(ro)]);
	}

	void build(int ro,int L,int R){
		maxv[ro] = 0;
		if (L == R){
			return ;
		}
		int M = (L + R) >> 1;
		build(lson(ro),L,M);
		build(rson(ro),M+1,R);
	}

	void update(int ro,int L,int R){
		if (L == R){
			maxv[ro] = max(maxv[ro],v);
			return ;
		}

		int M = (L + R) >> 1;
		if (ql <= M)	update(lson(ro),L,M);
		else	update(rson(ro),M+1,R);
		push_up(ro);

	}

	int query(int ro,int L,int R){
		if (ql <= L && R <= qr){
			return maxv[ro];
		}

		int M = (L + R) >> 1;
		int ans = 0;
		if (ql <= M)	ans = max(ans,query(lson(ro),L,M));
		if (M < qr)		ans = max(ans,query(rson(ro),M+1,R));
		return ans;
	}


}it;

void input(){
	scanf("%d%d",&N,&L);
	it.build(1,1,N);
	rep(i,1,N,1){
		scanf("%d",&a[i]);
		tem[i] = a[i];
	}
	sort(tem+1,tem+N+1);
	int siz = unique(tem+1,tem+N+1) - tem - 1;
	cls(h,0x7f);

	rep(i,1,N,1){
		int k = lower_bound(h+1,h+N+1,a[i]) - h;
		f[i] = k;
		h[k] = a[i];
	}

	cls(h,0x7f);

	pre(i,N,1,1){
		int k = lower_bound(h+1,h+N+1,-a[i]) - h;
		g[i] = k;
		h[k] = -a[i];
	}

	int ans = 0;
	a[N+1] = INF;
	g[N+1] = 0;
	rep(i,L+1,N+1,1){
		int k = lower_bound(tem+1,tem+siz+1,a[i]) - tem;
		it.ql = 1;
		it.qr = (k >1 ? k-1 : 1);
		ans = max(ans,it.query(1,1,N)+g[i]);
		k = lower_bound(tem+1,tem+siz+1,a[i-L]) - tem;
		it.ql = k;
		it.v = f[i-L];
		if (i <= N)
			it.update(1,1,N);
	}
	
	printf("%d\n",ans);

}

int main(){
	int t;
	int kase = 1;
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	scanf("%d",&t);
	while(t--){
		printf("Case #%d: ",kase++);
		input();
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值