杭电2019多校第五场 HDU——6635 Nonsense Time(思维动态lis)

You a given a permutation p1,p2,…,pnp1,p2,…,pn of size nn. Initially, all elements in pp are frozen. There will be nn stages that these elements will become available one by one. On stage ii, the element pkipki will become available. 

For each ii, find the longest increasing subsequence among available elements after the first ii stages.

Input

The first line of the input contains an integer T(1≤T≤3)T(1≤T≤3), denoting the number of test cases. 

In each test case, there is one integer n(1≤n≤50000)n(1≤n≤50000) in the first line, denoting the size of permutation. 

In the second line, there are nn distinct integers p1,p2,...,pn(1≤pi≤n)p1,p2,...,pn(1≤pi≤n), denoting the permutation. 

In the third line, there are nn distinct integers k1,k2,...,kn(1≤ki≤n)k1,k2,...,kn(1≤ki≤n), describing each stage. 

It is guaranteed that p1,p2,...,pnp1,p2,...,pn and k1,k2,...,knk1,k2,...,kn are generated randomly.

Output

For each test case, print a single line containing nn integers, where the ii-th integer denotes the length of the longest increasing subsequence among available elements after the first ii stages.

Sample Input

1
5
2 5 3 1 4
1 4 5 3 2

Sample Output

1 1 2 3 3

题意:给出一个固定数组,看样例固定数组就是2 5 3 1 4,然后每次可以用相应位置的数来求lis比如1 4 5 3 2,第一次只能用1位上的2,lis是1,然后能用1和4位置上的2,1,lis是1,所以题目就是求每次加一个相应位置的数的lis,即:动态lis

题解:考虑时光倒流,倒着求,求出lis,如果倒着来看的那个数,是lis里的数那么长度不变,把相应位置归0,如果是lis里的数,说明再往前面lis里的数要发生改变,这时再求一遍lis即可,然后重复上述操作。这样写下来看着最坏时间复杂度是:n^2*log(n),但是正版题解说:因为数是随机产生的,所以复杂度可以是:n*sqrt(n)*log(n)

上代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAX = 1e6+10;
int a[MAX],b[MAX],c[MAX],pos[MAX],ans[MAX],d[MAX];
int cnt,w,sum,n;
void solve(){
	cnt=sum=0;
	for (int i = 0; i <= n;i++) pos[i]=0;//这个位置数组别忘记初始化~~
	for (int i = 1; i <= n;i++){
   		if(a[i]==0) continue;//为0表示这个位置上的数还不能用
        if(cnt==0||a[i]>ans[cnt]){
            ans[++cnt]=a[i];
            pos[i]=cnt;//记录路径,a[i]这个数在哪儿个位置
        }
        else{
            int index=lower_bound(ans+1,ans+cnt+1,a[i])-ans;
            ans[index]=a[i];
            pos[i]=index;//记录路径,a[i]这个数在哪儿个位置
        }
    }
    w=cnt;
    int maxx=5201314;//因为今天七夕节,哈哈哈~~开玩笑的~~这个最大值不加也行
    sum=0;
    for (int i = n; i >= 1;i--){//存lis里有什么数
    	if(!cnt) break;
    	if(pos[i]==cnt&&maxx>a[i]){// 这个 maxx>a[i] 没有也可以
    		cnt--;
    		c[sum++]=a[i];
    		maxx=a[i];//不加也行,我是为了保证正确性,其实没啥鸟用
		}
	}
	sort(c,c+sum);//不从小到大排序没法用库函数二分
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for (int i = 1; i <= n;i++) scanf("%d",&a[i]);
        for (int i = 1; i <= n;i++) scanf("%d",&b[i]);
        solve();
		for (int i = n; i >= 1;i--){
			int index=lower_bound(c,c+sum,a[b[i]])-c;
			if(c[index]!=a[b[i]]){
				d[i]=w;//存长度
				a[b[i]]=0;//归0
				continue;
			}
			else {
				d[i]=w;//存长度
				a[b[i]]=0;//归0
				solve();
			}
		}
		for (int i = 1; i <= n;i++){
			if(i==1) printf("%d",d[i]);
			else printf(" %d",d[i]);
		}
		puts("");
    }
    return 0;
} 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心脏dance

如果解决了您的疑惑,谢谢打赏呦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值