hdu 3564(线段树+LIS)

来源:互联网 发布:软件测试的简历 编辑:程序博客网 时间:2024/05/21 02:50

题意:给出1~n的插入顺序,要求每次插入之后的LIS


解题思路:这道题确实挺难想的,我最开始想用树状数组每插入一个数就更新一次,如果这么想,那么你就输了。它这里的想法是先将1-n的最终位置都保存起来,然后再一个个去找LIS。这里有点离线算法的意思,至少了解到更新时可以先别急着处理。还有这里要总结一种线段树的用法,就是在空格处去填充数字,确实结合了这道题的特点把线段树用的很灵活。。。


参考的博客:http://blog.csdn.net/libin56842/article/details/13095801



#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn = 100005;struct Segment{int l,r;int cnt; //cnt记录空位的数量}tree[maxn<<2];int n,len,pos[maxn],ans[maxn],dp[maxn];void build(int rt,int l,int r){tree[rt].l = l, tree[rt].r = r;tree[rt].cnt = 1;if(l == r) return;int mid = (l + r) >> 1;build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);tree[rt].cnt = tree[rt<<1].cnt + tree[rt<<1|1].cnt;}void insert(int rt,int x,int m)//表示m要插入x的位置{if(tree[rt].l == tree[rt].r){ans[m] = tree[rt].l;tree[rt].cnt = 0;return;}tree[rt].cnt--;//要插入一个数,表示这段区间内有一个空会被占if(x <= tree[rt<<1].cnt)insert(rt<<1,x,m);else insert(rt<<1|1,x-tree[rt<<1].cnt,m);}int binsearch(int val){int l = 1, r = len, mid;while(l <= r){mid = (l + r) >> 1;if(val > dp[mid])l = mid + 1;else r = mid - 1;}return l;}int main(){int t,cas = 1;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i = 1; i <= n; i++){scanf("%d",&pos[i]);pos[i]++;dp[i] = 0;}build(1,1,n);for(int i = n; i >= 1; i--)//必须要逆着遍历,因为最后一个加入的数是可以确定位置的,倒数第二个数在最后一个数确定的情况下再找位置,以此类推insert(1,pos[i],i);//也就是说,越往后加入进来的数,它选择位置的权利更大,这是种逆向思维printf("Case #%d:\n",cas++);len = 0;for(int i = 1; i <= n; i++){int k = binsearch(ans[i]);len = max(len,k);dp[k] = ans[i];printf("%d\n",len);}printf("\n");}return 0;}


0 0
原创粉丝点击