hdu4521之线段树单点更新

来源:互联网 发布:明朝三百年 知乎 编辑:程序博客网 时间:2024/05/19 23:19

http://acm.hdu.edu.cn/showproblem.php?pid=4521


#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<string>#include<queue>#include<algorithm>#include<map>#include<iomanip>#define INF 99999999using namespace std;const int MAX=100000+10;int sum[MAX<<2];//表示区间内以叶子值结束的最长子序列int len[MAX];//表示以第i个数结束的最长子序列int s[MAX];void Update(int pos,int date,int n,int left,int right){if(left == right){sum[n]=date;return;}int mid=left+right>>1;if(pos<=mid)Update(pos,date,n<<1,left,mid);else Update(pos,date,n<<1|1,mid+1,right);sum[n]=max(sum[n<<1],sum[n<<1|1]);//更新区间内最长子序列(以某个叶子结束的序列) }int Query(int L,int R,int n,int left,int right){if(L<=left && right<=R)return sum[n];int mid=left+right>>1,lmax=0,rmax=0;if(L<=mid)lmax=Query(L,R,n<<1,left,mid);if(R>mid)rmax=Query(L,R,n<<1|1,mid+1,right);return max(lmax,rmax);//返回这个区间内的最长子序列 }int main(){//O(nlogn)复杂度 int n,d;while(cin>>n>>d){memset(sum,0,sizeof sum);int maxlen=0;for(int i=1;i<=n;++i){scanf("%d",s+i);if(i-d-1>0)Update(s[i-d-1],len[i-d-1],1,0,MAX);//更新恰好满足第i个位置的数i-d-1 if(s[i]>0)len[i]=Query(0,s[i]-1,1,0,MAX)+1;//查询在s[i]出现之前出现的数且以该数结束的最长子序列 else len[i]=1;//在s[i]之前出现的数s[k]一定满足i-k>d,因为插入(更新)的时候是根据i-d-1更新的,i-(k-d-1)=d+1+(i-k)>dmaxlen=max(maxlen,len[i]);}cout<<maxlen<<endl;}return 0;}