BZOJ 3904 最长上升子序列 lkids 线段树

题目大意:给定一个序列,求以较小数开始的锯齿子序列,使相邻两项之间差值不小于k

令f[i][0]表示第i个数为序列中的较大值的最长子序列

f[i][1]表示第i个数为序列中的较小值的最长子序列

暴力转移是O(n^2)的

我们发现决策点的值都是连续的一段区间 因此用线段树维护一下就行了

(真简略)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 200200
using namespace std;
template<int _> struct Segtree{
	Segtree *ls,*rs;
	int val;
	Segtree():ls(0x0),rs(0x0),val(_) {}
	friend void Update(Segtree *&p,int x,int y,int l,int r,int val)
	{
		int mid=x+y>>1;
		if(!p) p=new Segtree;
		if(x==l&&y==r)
		{
			p->val=max(p->val,val);
			return ;
		}
		if(r<=mid)
			Update(p->ls,x,mid,l,r,val);
		else if(l>mid)
			Update(p->rs,mid+1,y,l,r,val);
		else
			Update(p->ls,x,mid,l,mid,val) , Update(p->rs,mid+1,y,mid+1,r,val);
	}
	friend int Get_Ans(Segtree *p,int x,int y,int pos)
	{
		int mid=x+y>>1;
		if(!p) return _;
		if(x==y) return p->val;
		if(pos<=mid)
			return max(Get_Ans(p->ls,x,mid,pos),p->val);
		else
			return max(Get_Ans(p->rs,mid+1,y,pos),p->val);
	}
};
Segtree< 0> *tree0=new Segtree< 0>;
Segtree<-1> *tree1=new Segtree<-1>;
int n,k,ans;
int a[M],f[M][2];
int main()
{
	int i;
	cin>>n>>k;
	for(i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		if(a[i]-k>=0)
		{
			f[i][0]=Get_Ans(tree1,0,100000000,a[i]-k)+1;
			Update(tree0,0,100000000,0,a[i],f[i][0]);
		}
		if(a[i]+k<100000000)
		{
			f[i][1]=Get_Ans(tree0,0,100000000,a[i]+k)+1;
			Update(tree1,0,100000000,a[i],100000000,f[i][1]);
		}
		ans=max(ans,f[i][0]);
		ans=max(ans,f[i][1]);
	}
	cout<<ans<<endl;
	return 0;
}
时间: 2024-10-17 20:27:45

BZOJ 3904 最长上升子序列 lkids 线段树的相关文章

D. Babaei and Birthday Cake---cf629D(最长上升子序列和+线段树优化)

http://codeforces.com/problemset/problem/629/D 题目大意: 我第一反应就是求最长上升子序列和  但是数值太大了  不能直接dp求  可以用线段树优化一下 #include<stdio.h> #include<string.h> #include<stdio.h> #include<math.h> #include<iostream> #include<algorithm> using na

BZOJ 2434 最长公共子序列

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2423 题意:求两个串的LCS以及LCS的个数. 思路: int f[2][N],g[2][N]; char s[N],t[N]; int n,m; void add(int &x,int y) { x+=y; x%=mod; } int main() { RD(s); n=strlen(s)-1; RD(t); m=strlen(t)-1; int i,j; int pre=0,cur

HDU 1025-Constructing Roads In JGShining&#39;s Kingdom(最长不降子序列,线段树优化)

分析: 最长不降子序列,n很大o(n^2)肯定超,想到了小明序列那个题用线段树维护前面的最大值即可 该题也可用二分搜索来做. 注意问题输出时的坑,路复数后加s #include <map> #include <set> #include <list> #include <cmath> #include <queue> #include <stack> #include <cstdio> #include <vecto

BZOJ 2877 NOI2012 魔幻棋盘 二维线段树

题目大意:给定一个矩阵,支持两种操作: 1.将某个子矩阵中的每个值增加一个数 2.询问某个子矩阵中的所有数的GCD 已知所有询问恒过定点(x,y) 算了BZOJ没有原题我还是把原题发上来吧- - <论代码长度与注释长度以及题目简单程度的比例失调关系以及日本饮用水资源的解决方案> <10K+代码是怎样炼成的> <GCD与修改标记的正确用法> <出题人我*你吗系列> <懒惰即美德> 咳咳. 首先我们可以维护一个二维线段树支持子矩阵修改和子矩阵查询 但

bzoj 1798: [Ahoi2009]Seq 维护序列seq 线段树 区间乘法区间加法 区间求和

1798: [Ahoi2009]Seq 维护序列seq Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1798 Description 老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: (1)把数列中的一段数全部乘一个值; (2)把数列中的一段数全部加一个值; (3)询问数列

BZOJ_2124_等差子序列_线段树+Hash

Description 给一个1到N的排列{Ai},询问是否存在1<=p1<p2<p3<p4<p5<…<pLen<=N (Len>=3), 使得Ap1,Ap2,Ap3,…ApLen是一个等差序列. Input 输入的第一行包含一个整数T,表示组数. 下接T组数据,每组第一行一个整数N,每组第二行为一个1到N的排列,数字两两之间用空格隔开. N<=10000,T<=7 Output 对于每组数据,如果存在一个等差子序列,则输出一行“Y”,否则

18.10.9 不好做的最长上升子序列(nlogn树状数组解LIS)

描述 一个数的序列bi,当b1 < b2 < ... < bS的时候,我们称这个序列是上升的.对于给定的一个序列(a1, a2, ..., aN),我们可以得到一些上升的子序列(ai1, ai2, ..., aiK),这里1 <= i1 < i2 < ... < iK <= N.比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等.这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8

Codeforces 527C Glass Carving (最长连续0变形+线段树)

Leonid wants to become a glass carver (the person who creates beautiful artworks by cutting the glass). He already has a rectangular w mm ?×? h mm sheet of glass, a diamond glass cutter and lots of enthusiasm. What he lacks is understanding of what t

【BZOJ 3133】 3133: [Baltic2013]ballmachine (线段树+倍增)

3133: [Baltic2013]ballmachine Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 148  Solved: 66 Description 有一个装球机器,构造可以看作是一棵树.有下面两种操作: 从根放入一个球,只要下方有空位,球会沿着树滚下.如果同时有多个点可以走,那么会选择编号最小的节点所在路径的方向.比如依次在树根4放2个球,第一个球会落到1,第二个会落到3: 从某个位置拿走一个球,那么它上方的球会落下来.比如依次拿走