【HDU4521】 dp思想+线段树操作

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4521

题目大意:有n个数,求间距大于d的最长递增子序列。

 

解题思路:扎眼一看,不是简单的dp嘛,再眨眼一看,n最大为10^5,蛋碎一地呀。

              这题不仅要线段树功底好,还要有比较强的dp思想,从第d+1个位置开始更新,每个节点的sum值保存的是从第1个数到当前数的最长符合要求的子序列,查询的时候只需查询线段树中值在其左边的最大的sum[u](最长符合要求序列)。

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <queue>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 #define lz 2*u,l,mid
 9 #define rz 2*u+1,mid+1,r
10 const int maxn=110000;
11 int sum[2*maxn], dp[maxn+5], a[maxn+5];
12 
13 void Update(int u, int l, int r, int p, int c)
14 {
15     sum[u]=max(sum[u],c);
16     if(l==r)return ;
17     int mid=(l+r)>>1;
18     if(p<=mid) Update(lz,p,c);
19     else Update(rz,p,c);
20 }
21 
22 int Query(int u, int l, int r, int tl, int tr)
23 {
24     if(tl>tr) return 0;
25     if(tl<=l&&r<=tr) return sum[u];
26     int mid=(l+r)>>1;
27     if(tr<=mid) return Query(lz,tl,tr);
28     else if(tl>mid) return Query(rz,tl,tr);
29     else
30     {
31         int t1=Query(lz,tl,mid);
32         int t2=Query(rz,mid+1,tr);
33         return max(t1,t2);
34     }
35 }
36 
37 int main()
38 {
39     int n, d;
40     while(scanf("%d%d",&n,&d)!=EOF)
41     {
42         memset(sum,0,sizeof(sum));
43         for(int i=1; i<=n; i++)
44             scanf("%d",a+i);
45         int maxx=0;
46         for(int i=1; i<=n; i++)
47         {
48             if(i>d+1) Update(1,1,maxn,a[i-d-1]+1,dp[i-d-1]);  ///注意a[i-d-1]要加1
49             dp[i]=Query(1,1,maxn,1,a[i])+1;
50             maxx=max(dp[i],maxx);
51         }
52         printf("%d\n",maxx);
53     }
54     return 0;
55 }

 

posted @ 2013-03-30 18:16  Mr. Ant  阅读(726)  评论(0编辑  收藏  举报