题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4521
题意:中文题,不解释
题解:这题就是LIS的加强版,可以用二分的nlogn来做,也可以用线段树的nlogn 做这个带间隔的LIS,具体看代码
1 #include2 #include 3 #define root 1,n,1 4 #define ls l,m,rt<<1 5 #define rs m+1,r,rt<<1|1 6 #define F(i,a,b) for(int i=a;i<=b;i++) 7 using namespace std; 8 const int N=1e5+7; 9 int n=N-1,sum[N<<2],a[N],ans,dp[N],d,nn; 10 11 void update(int x,int k,int l,int r,int rt){ 12 if(l==r){sum[rt]=k;return;} 13 int m=(l+r)>>1; 14 if(x<=m)update(x,k,ls); 15 else update(x,k,rs); 16 sum[rt]=max(sum[rt<<1],sum[rt<<1|1]); 17 } 18 19 int query(int L,int R,int l,int r,int rt){ 20 if(L>R)return 0; 21 if(L<=l&&r<=R)return sum[rt]; 22 int m=(l+r)>>1,ret=0; 23 if(L<=m)ret=max(ret,query(L,R,ls)); 24 if(m max(ret,query(L,R,rs)); 25 return ret; 26 } 27 28 int main(){ 29 while(~scanf("%d%d",&nn,&d)){ 30 F(i,1,nn)scanf("%d",a+i); 31 F(i,0,(N<<2)-1)sum[i]=0;ans=0; 32 F(i,1,nn){ 33 if(i>d+1)update(a[i-d-1]+1,dp[i-d-1],root); 34 dp[i]=query(1,a[i],root)+1; 35 ans=max(dp[i],ans); 36 } 37 printf("%d\n",ans); 38 } 39 return 0; 40 } 41 /* 42 状态方程很好想,dp[i] = max(dp[j] + 1)其中a[i] > a[j] 43 44 我们把以第i个元素为结尾的最长上升子序列放到线段树对应值为 45 a[i]的叶子上(有点hash思想,这是为了保证上升这个特性,查询的 46 时候方便),当然如果此时的i-d<=1就不用插入了,这时候用不到任 47 何的前置状态。 48 49 需要用我们就插入一次,而且每次插入我们都能保证那个点和当前点i 50 的距离一定大于d(之前已经空了d个位置),到时就直接去线段树上小 51 于a[i]的区间找最大值就行了 52 */