题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3173
题解:话说这道题好像是用splay还是treap来模拟啊,可是我完全不会这两种算法啊。。。无奈,只能去学习了另一种 巧妙的办法。。。。
1.首先我们先得到最终队列的样子,第i个位置的数字为*i;
2.按照队列的顺序,i递增,我们用f[*i]来表示当插入*i这个数后,以*i为结尾的最长上升子序列的长度,用k[*i]来储存当前这个数未更新前f[1~*i]中的最大值,我们都知道,平常更新答案是f[i]=max(f[j]+1)即当j<i且*j<*i;那么因为这道题符合一个性质,就是我们是按数字的最终位置一个个插入的,所以我们保证只要f[j]不为0(j<i),那么j这个数字一定在i之前就已经做过了(if (f[j]>0) *j<*i);所以f[*i]一定等于k[*i]+1;
3.*i这个数字最后的答案为max(f[1~*i]);(因为题目是按数字的大小一个个插入的,所以最优解的结尾数字一定小于等于*i,毕竟其他数字都还没插入。。)
为了降低时间复杂度,我们用树状数组来维护k数组,复杂度为O(nlogn);
然后为了方便得出最终的队列的顺序,我学习了如何使用vector,当然,这个时间就变得慢多了。。。
#include<cstdio> #include<cstring> #include<iostream> #include<vector> using namespace std; int k[2000000],n,p[2000000],f[2000000]; int lowbit(int x) { return (x&-x); } int query(int x) { int tot=0; while (x>0) { tot=max(tot,k[x]); x-=lowbit(x); } return tot; } void update(int x,int v) { while (x<n) { k[x]=max(k[x],v); x+=lowbit(x); } } int main() { scanf("%d",&n); int w; vector<int>a; for (int i=1;i<=n;i++) { scanf("%d",&w); a.insert(a.begin()+w,i);//往vector里面插入 } for (vector<int>::iterator i=a.begin();i!=a.end();i++) { //*i表示在a的里面的第i个元素的值 //查询max(f[1~*i]); f[*i]=query(*i)+1; //用树状数组来维护k数组 update(*i,f[*i]); } for (int i=1;i<=n;i++) { f[i]=max(f[i-1],f[i]); //得出最后的答案 printf("%d\n",f[i]); } return 0; }