题意:有多组测试数据,每组数据的n和d表示,有n个数,求间距大于d的最长上升序列。(1<=n<=10^5 , 0<=d<=10^5)
如果数据范围比较小,就是一比较水的DP了。但是10^5级别的数据,O(n^2)的复杂度显然不科学。
用线段树搞定。线段树中叶子结点表示值为i的并且以其结束的最长上升序列是多少。每次转移的时候,查询比当前值小的最大值就可以了。
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N=1e5+5; #define LL(x) (x<<1) #define RR(x) (x<<1|1) #define MID(a,b) (a+((b-a)>>1)) int a[N],imx[N]; struct Segtree { struct node { int lft,rht,mx; int mid(){return MID(lft,rht);} }tree[N*4]; void build(int lft,int rht,int ind) { tree[ind].lft=lft; tree[ind].rht=rht; tree[ind].mx=0; if(lft!=rht) { int mid=tree[ind].mid(); build(lft,mid,LL(ind)); build(mid+1,rht,RR(ind)); } } void updata(int pos,int ind,int valu) { if(tree[ind].lft==tree[ind].rht) tree[ind].mx=max(tree[ind].mx,valu); else { int mid=tree[ind].mid(); if(pos<=mid) updata(pos,LL(ind),valu); if(pos> mid) updata(pos,RR(ind),valu); tree[ind].mx=max(tree[LL(ind)].mx,tree[RR(ind)].mx); } } int query(int st,int ed,int ind) { int lft=tree[ind].lft,rht=tree[ind].rht; if(st<=lft&&rht<=ed) return tree[ind].mx; else { int mid=tree[ind].mid(); int mx1=0,mx2=0; if(st<=mid) mx1=query(st,ed,LL(ind)); if(ed> mid) mx2=query(st,ed,RR(ind)); return max(mx1,mx2); } } }seg; int main() { int n,d; while(scanf("%d%d",&n,&d)!=EOF) { int ans=0,ed=0; for(int i=0;i<n;i++) { scanf("%d",&a[i]); ed=max(ed,a[i]); } seg.build(0,ed,1); for(int i=0;i<n;i++) { if(i-d-1>=0) seg.updata(a[i-d-1],1,imx[i-d-1]); if(a[i]>0) imx[i]=seg.query(0,a[i]-1,1)+1; else imx[i]=1; ans=max(ans,imx[i]); } printf("%d\n",ans); } return 0; }