【bzoj3173】[Tjoi2013]最长上升子序列

Description

给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?

Input

第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)

Output

N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。

Sample Input

3
0 0 2

Sample Output

1
1
2

HINT

100%的数据 n<=100000

易得,令f[i]表示以数字i结尾的最长上升子序列长度,则新加入一个数时不会影响到其他的f[i]。

在线写法:用平衡树直接模拟,每一次用位置的前缀f[i]的最大值+1来作为当前的新加入的数的f[i],然后将其插入到指定位置。输出答案时直接查找当前所有f[i]的最大值。

离线写法:求出最终序列然后nlogn求一次LIS即可,可以用树状数组或平衡树实现。

【fhq-treap 在线】

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdlib>
 5 using namespace std;
 6 const int N=1e5+5;
 7 int n,root,cnt,rt1,rt2,pos,ch[N][6];
 8 #define lc ch][0
 9 #define rc ch][1
10 #define rnd ch][2
11 #define sz ch][3
12 #define v ch][4
13 #define mx ch][5
14 int read()
15 {
16     int x=0,f=1;char c=getchar();
17     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
18     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
19     return x*f;
20 }
21 void up(int w)
22 {
23     w[sz]=w[lc][sz]+w[rc][sz]+1;
24     w[mx]=max(w[lc][mx],w[rc][mx]);
25     w[mx]=max(w[mx],w[v]);
26 }
27 void split(int w,int& l,int& r,int k)
28 {
29     if(!w){l=r=0;return;}
30     int lson=w[lc][sz];
31     if(k<=lson){r=w;split(w[lc],l,w[lc],k);}
32     else {l=w;split(w[rc],w[rc],r,k-lson-1);}
33     up(w);
34 }
35 int merge(int a,int b)
36 {
37     if(!a||!b)return a+b;
38     if(a[rnd]<b[rnd]){a[rc]=merge(a[rc],b);up(a);return a;}
39     else {b[lc]=merge(a,b[lc]);up(b);return b;}
40 }
41 void ins(int& w,int x,int k)
42 {
43     if(x[rnd]<w[rnd]||!w){split(w,x[lc],x[rc],k);w=x;up(w);return;}
44     int lson=w[lc][sz];
45     if(k<=lson)ins(w[lc],x,k);
46     else ins(w[rc],x,k-lson-1);
47     up(w);
48 }
49 int query(int pos)
50 {
51     rt1=rt2=0;split(root,rt1,rt2,pos);
52     int ans=rt1[mx];root=merge(rt1,rt2);
53     return ans;
54 }
55 int main()
56 {
57     n=read();
58     for(int i=1;i<=n;i++)
59     {
60         pos=read();
61         cnt++;cnt[v]=query(pos)+1;
62         cnt[sz]=1;cnt[rnd]=rand();
63         ins(root,cnt,pos);
64         printf("%d\n",root[mx]);
65     }
66     return 0;
67 }

【树状数组 离线】

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int N=1e5+5;
 6 int n,id,cnt,f[N],ans[N],a[N],num[N],bit[N];
 7 int read()
 8 {
 9     int x=0,f=1;char c=getchar();
10     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
11     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();}
12     return x*f;
13 }
14 int lowbit(int x){return x&(-x);}
15 void ins(int x){while(x<=n)bit[x]--,x+=lowbit(x);}
16 int pos(int x)
17 {
18     int now=0,ans=0;
19     for(int i=17;i>=0;i--)
20     {
21         now+=(1<<i);
22         if(now<n&&ans+bit[now]<x)ans+=bit[now];
23         else now-=(1<<i);
24     }
25     return now+1;
26 }
27 int main()
28 {
29     n=read();
30     for(int i=1;i<=n;i++)
31     {
32         a[i]=read();bit[i]++;
33         if(i+lowbit(i)<=n)bit[i+lowbit(i)]+=bit[i];
34     }
35     for(int i=n;i>=1;i--)
36         id=pos(a[i]+1),num[id]=i,ins(id);
37     for(int i=1;i<=n;i++)
38     {
39         id=lower_bound(f+1,f+cnt+1,num[i])-f;
40         if(id>cnt)f[++cnt]=num[i];
41         else f[id]=num[i];
42         ans[num[i]]=id;
43     }
44     for(int i=1;i<=n;i++)ans[i]=max(ans[i],ans[i-1]),printf("%d\n",ans[i]);
45     return 0;
46 }

时间: 2024-10-29 05:27:33

【bzoj3173】[Tjoi2013]最长上升子序列的相关文章

[BZOJ3173][Tjoi2013]最长上升子序列

试题描述 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? 输入 第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N) 输出 N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少. 输入示例 3 0 0 2 输出示例 1 1 2 数据规模及约定 100%的数据 n<=

BZOJ3173: [Tjoi2013]最长上升子序列 Treap 平衡树

Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N) Output N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少. Sample Input 3 0 0 2 Sample Outp

BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]

3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1613  Solved: 839[Submit][Status][Discuss] Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk

BZOJ 3173: [Tjoi2013]最长上升子序列

3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1524  Solved: 797[Submit][Status][Discuss] Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk

BZOJ 3173: [Tjoi2013]最长上升子序列( BST + LIS )

因为是从1~n插入的, 慢插入的对之前的没有影响, 所以我们可以用平衡树维护, 弄出最后的序列然后跑LIS就OK了 O(nlogn) -------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x, c) memset(x, c, sizeof(x))

bzoj 3173: [Tjoi2013]最长上升子序列(splay)

3173: [Tjoi2013]最长上升子序列 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 1315  Solved: 682 [Submit][Status][Discuss] Description 给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? Input 第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字

P4309 [TJOI2013]最长上升子序列

题目 P4309 [TJOI2013]最长上升子序列 做法 最长上升序列的求法肯定是烂大街了 水题是肯定的,确定出序列的位置然后套个树状数组就好了(强制在线的话改成线段树维护前缀最值也行) 所以说这题其实难点在与怎么让代码简洁,见识到一个新的\(STL\):\(rope\) My complete code #include<bits/stdc++.h> #include<ext/rope> using namespace std; typedef int LL; const LL

【bzoj3173】最长上升子序列

Portal --> bzoj3173 Solution 感觉自己需要智力康复qwq 首先题目给的这个序列肯定是一个\(1-n\)的排列,并且插入的顺序是从小到大 仔细思考一下会发现如果知道了最终的序列,问题就比较好解决了,这里提供一种用线段树的做法: 如果知道了最终的序列,记数字\(i\)在该序列中的位置为\(loc[i]\),那么我们按照\(i\)从小到大的顺序,查询结尾在\([1,loc[i])\)的这段位置中的最长上升子序列的最大值\(mx\),并将\(mx+1\)作为以\(loc[i]

BZOJ 3173 [Tjoi2013] 最长上升子序列 解题报告

这个题感觉比较简单,但却比较容易想残.. 我不会用树状数组求这个原排列,于是我只好用线段树...毕竟 Gromah 果弱马. 我们可以直接依次求出原排列的元素,每次找到最小并且最靠右的那个元素,假设这是第 $i$ 次找的,那么这就是原排列的第 $i$ 项,然后我们就把这个元素删去(变成很大的数),再把这个数以左的数都加 1,进行下一轮. 然后就是裸的最长上升子序列啦~~~ 时间复杂度 $O(n\log n)$,空间复杂度 $O(n)$. 1 #include <cstdio> 2 #inclu