先是nlogn的LIS解法
/*
LIS nlogn解法
*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
//结尾的数字越小,说明相同长度下当前序列越优
int lis[100005],a[100005];//lis[i]表示长度为i的最优的结尾数
int n,len=0;
int find(int x){//找到lis中第一个大于等于x的数的下标
int l=0,r=len;
while(l<r){
int mid=l+r>>1;
if(lis[mid]>=x)
r=mid;
else l=mid+1;
}
return l;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
lis[1]=a[1];len++;
for(int i=2;i<=n;i++){//按顺序处理每一个数
if(a[i]>lis[len])//可以更新新长度了
lis[++len]=a[i];
else{//对于一个a[i],可以更新以它为结尾的最长lis的结尾
int pos=find(a[i]);//找到lis中第一个大于等于a[i]的数,pos也是以那个数结尾的长度
lis[pos]=a[i]; //把那个数替换了
}
}
printf("%d\n",len);
return 0;
}
线段树解LIS
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 10005
int len[maxn<<2];
int dp[maxn];
int a[maxn];
void build(int l,int r,int rt){
if(l==r){
len[rt]=0;
return;
}
int m=l+r>>1;
build(lson);
build(rson);
}
void pushup(int rt){
len[rt]=max(len[rt<<1],len[rt<<1|1]);
}
void update(int pos,int val,int l,int r,int rt){
if(l==r){
len[rt]=val;
return;
}
int m=l+r>>1;
if(pos<=m) update(pos,val,lson);
else update(pos,val,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l && R>=r){
return len[rt];
}
int m=l+r>>1;
if(R<=m) return query(L,R,lson);
else if(L>=m) return query(L,R,rson);
return max(query(L,m,lson),query(m+1,R,rson));
}
int main(){
int n;
while(scanf("%d",&n)==1){
int temp=-1;
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
temp=max(temp,a[i]);
}
build(0,temp,1);
int ans=0;
//找到以小于a[i]的值为结尾的lis,值+1保存在dp[i]中,下一步再把这个dp值更新到线段树中
for(int i=1;i<=n;i++){
if(i!=1) update(a[i-1],dp[i-1],0,temp,1);
if(a[i]>=1)
dp[i]=query(0,a[i]-1,0,temp,1)+1;
else dp[i]=1;//a[i]是0的情况
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}
return 0;
}
hdu4521 求间隔为d的lis
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 100010
int a[maxn],dp[maxn],n,d;//用dp存储以第i个数为结尾的lis
int tree[maxn<<2];//保存以【l,r】结尾的lis
inline void pushup(int rt){
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]=0;
return;
}
int m=l+r>>1;
build(lson);
build(rson);
pushup(rt);
}
//把val更新到pos位置,以pos值结尾的lis为val
void update(int pos,int val,int l,int r,int rt){
if(l==r){
tree[rt]=val;
return;
}
int m=l+r>>1;
if(pos<=m)
update(pos,val,lson);
else
update(pos,val,rson);
pushup(rt);
}
//查询值在【L,R】之间的最大lis
int query(int L,int R,int l,int r,int rt){
if(L<=l && R>=r){
return tree[rt];
}
int m=l+r>>1,ret=-1;
if(R<=m) return query(L,R,lson);
else if(L>m) return query(L,R,rson);
else return max(query(L,m,lson),query(m+1,R,rson));
// return ret;
}
int main(){
int temp,ans;
while(scanf("%d%d",&n,&d)==2){
ans=temp=-1;
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
temp=max(temp,a[i]);//找到最大的值
}
build(0,temp,1);//线段树的区间是0-temp,必须从0开始
for(int i=1;i<=n;i++){
if(i-d-1>=1)//必须相隔d+1及以上,把这个点更新进去
update(a[i-d-1],dp[i-d-1],0,temp,1);
if(a[i]>=1)//找到之前更新以数值小于a[i]为结尾的最长lis
dp[i]=query(0,a[i]-1,0,temp,1)+1;
else dp[i]=1;
ans=max(ans,dp[i]);
}
printf("%d\n",ans);
}
}
来源:https://www.cnblogs.com/zsben991126/p/9893286.html