hdu_4521_小明系列问题——小明序列(LIS)

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

题意:中文题,不解释

题解:这题就是LIS的加强版,可以用二分的nlogn来做,也可以用线段树的nlogn 做这个带间隔的LIS,具体看代码

 1 #include
 2 #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(mmax(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 */
View Code

 


 

转载于:https://www.cnblogs.com/bin-gege/p/5696109.html

你可能感兴趣的:(php,数据结构与算法)