hdu 3564(线段树+LIS)
生活随笔
收集整理的這篇文章主要介紹了
hdu 3564(线段树+LIS)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題意:給出1~n的插入順序,要求每次插入之后的LIS
解題思路:這道題確實(shí)挺難想的,我最開始想用樹狀數(shù)組每插入一個(gè)數(shù)就更新一次,如果這么想,那么你就輸了。它這里的想法是先將1-n的最終位置都保存起來,然后再一個(gè)個(gè)去找LIS。這里有點(diǎn)離線算法的意思,至少了解到更新時(shí)可以先別急著處理。還有這里要總結(jié)一種線段樹的用法,就是在空格處去填充數(shù)字,確實(shí)結(jié)合了這道題的特點(diǎn)把線段樹用的很靈活。。。
參考的博客: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記錄空位的數(shù)量 }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--; //要插入一個(gè)數(shù),表示這段區(qū)間內(nèi)有一個(gè)空會(huì)被占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--) //必須要逆著遍歷,因?yàn)樽詈笠粋€(gè)加入的數(shù)是可以確定位置的,倒數(shù)第二個(gè)數(shù)在最后一個(gè)數(shù)確定的情況下再找位置,以此類推insert(1,pos[i],i); //也就是說,越往后加入進(jìn)來的數(shù),它選擇位置的權(quán)利更大,這是種逆向思維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; }
總結(jié)
以上是生活随笔為你收集整理的hdu 3564(线段树+LIS)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu 3172(并查集+hash)
- 下一篇: 【开发工具】 JEECG_3.7新版开发