洛谷P4309 [TJOI2013]最长上升子序列

博客讨论了如何解决一个关于最长上升子序列的问题,其中涉及在给定序列中按特定位置插入数字。每插入一个数字,需要找出当前最长上升子序列的长度。解决方案建议从后往前考虑,使用二分查找确定每个数字的正确位置,并更新最长上升子序列的长度。

Description

给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?


Input

第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)


Output

N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。


Solution

因为后插进去的优先级更高,考虑倒序解决这个问题。
通过倒序插入确定了每一个点的真正位置。

不过需要注意后面已经插入的对前面的影响。
所以通过二分确定位置pos。
答案pos=后面在位置pos前插的个数+这次操作插的位置x

然后按正常逆序对做就行了。


Code

#include<bits/stdc++.h>
using namespace std;
int a[210010],n;
int pos[210010];
int sum[210010];
int p[210010];
int lowbit(int x){
	return x&-x;
}
void add(int pos,int x){
	for(int i=pos;i<=n;i+=lowbit(i))
	sum[i]=max(sum[i],x);
}
void add1(int x){
	for(int i=x;i<=n;i+=lowbit(i))
	pos[i]++;
}
int query(int x){
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
	ans=max(ans,sum[i]);
	return ans;
}
int query1(int x){
	int ans=0;
	for(int i=x;i;i-=lowbit(i))
	ans+=pos[i];
	return ans;
}
int get(int x){
	int l=x,r=n,ans=x;
    while(l<=r){
        int mid=(l+r)/2;
        if(query1(mid)<=mid-x) ans=mid,r=mid-1;
        else l=mid+1;
    }
	return ans;
}
int main(){
	int ans=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]),a[i]++;
	for(int i=n;i;i--){
		p[i]=get(a[i]);
		add1(p[i]);
	}
	for(int i=1;i<=n;i++){
		int x=query(p[i]-1)+1;
		add(p[i],x);
		ans=max(ans,x);
		printf("%d\n",ans);
	}
}
/*
7
5
1
1
1
0
0
2
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值