bzoj3173 最長上公升子串行

2022-05-09 12:48:09 字數 1682 閱讀 7265

portal --> bzoj3173

solution

感覺自己需要智力**qwq

首先題目給的這個序列肯定是乙個\(1-n\)的排列,並且插入的順序是從小到大

仔細思考一下會發現如果知道了最終的序列,問題就比較好解決了,這裡提供一種用線段樹的做法:

如果知道了最終的序列,記數字\(i\)在該序列中的位置為\(loc[i]\),那麼我們按照\(i\)從小到大的順序,查詢結尾在\([1,loc[i])\)的這段位置中的最長上公升子串行的最大值\(mx\),並將\(mx+1\)作為以\(loc[i]\)位置為結尾的答案,插入到線段樹中\(loc[i]\)對應的節點裡,複雜度是\(o(nlogn)\)

然後現在的問題是怎麼求最終的序列

這個可以用平衡樹來寫,不過其實也可以用線段樹來寫

考慮反過來確定每乙個數在最終序列中的位置,因為是反過來考慮的,所以一開始的時候每乙個位置都有乙個數,然後我們根據讀入的插入位置,按照\(n-1\)的順序,找到當前這個數的位置,然後將它刪掉(也就是對應的線段樹節點的\(sum-1\))

​  具體一點就是比如當前考慮到第\(i\)個數,讀入這個數應該要插入在\(a[i]\)的位置後面,也就是應該在當前這個序列的第\(a[i]+1\)個位置,那麼找到這個位置,然後把這個位置刪掉,這樣就可以得到還沒有插入這個數之前的序列的位置集合了,這部分的複雜度也是\(o(nlogn)\)的

​  然後就十分愉快地做完啦

**大概長這個樣子

#include#include#includeusing namespace std;

const int maxn=100010,seg=maxn*4;

namespace seg

void _build(int x,int l,int r)

int mid=l+r>>1;

ch[x][0]=++tot; _build(ch[x][0],l,mid);

ch[x][1]=++tot; _build(ch[x][1],mid+1,r);

pushup(x);

} void build(int _n)

void _update(int x,int d,int lx,int rx,int delta)

int mid=lx+rx>>1;

if (d<=mid) _update(ch[x][0],d,lx,mid,delta);

else _update(ch[x][1],d,mid+1,rx,delta);

pushup(x);

} void update(int d,int delta)

int _query_mx(int x,int l,int r,int lx,int rx)

int query(int l,int r)

int _get_loc(int x,int lx,int rx,int k)

int get_loc(int k)

};/*}}}*/

int loc[maxn],a[maxn],b[maxn];

int n,m,ans;

int main()

for (int i=1;i<=n;++i) a[loc[i]]=i;

seg::build(n);

ans=0;

int tmp;

for (int i=1;i<=n;++i)

}

bzoj 3173 最長上公升子串行

給定乙個序列,初始為空。現在我們將1到n的數字插入到序列中,每次將乙個數字插入到乙個特定的位置。每插入乙個數字,我們都想知道此時最長上公升子串行長度是多少?第一行乙個整數n,表示我們要將1到n插入序列中,接下是n個數字,第k個數字xk,表示我們將k插入到位置xk 0 xk k 1,1 k n n行,...

最長上公升子串行

問題描述 乙個數的序列bi,當b1 b2 bs的時候,我們稱這個序列是上公升的。對於給定的乙個序列 a1,a2,an 我們可以得到一些上公升的子串行 ai1,ai2,aik 這裡1 i1 i2 ik n。比如,對於序列 1,7,3,5,9,4,8 有它的一些上公升子串行,如 1,7 3,4,8 等等...

最長上公升子串行

最長上公升子串行問題是各類資訊學競賽中的常見題型,也常常用來做介紹動態規劃演算法的引例,筆者接下來將會對poj上出現過的這類題目做乙個總結,並介紹解決lis問題的兩個常用 演算法 n 2 和 nlogn 問題描述 給出乙個序列a1,a2,a3,a4,a5,a6,a7.an,求它的乙個子串行 設為s1...