杨氏矩阵更像一个维护最长上升子序列的数据结构,
实际上最长上升子序列的
O
(
n
log
n
)
O(n\log n )
O(nlogn)的单调栈解法就是维护杨表的第一行。。。
所以杨表就是最长上升子序列的究极工具。
推荐阅读
I
O
I
2019
IOI2019
IOI2019国家集训队论文 袁方舟的那篇。
例题:
C
T
S
C
2017
最
长
上
升
子
序
列
CTSC2017最长上升子序列
CTSC2017最长上升子序列
我们可以只维护杨表的前
n
n
n行和前
n
n
n列,并且可以由这些信息得到全部的杨表。注意杨表的前
n
n
n列我们可以通过把大小关系反转(将
<
<
<和
>
>
>的定义交换)后插入数字,得到的新杨表的前
n
n
n行就是原杨表转置后的前
n
n
n列。
A
C
C
o
d
e
\rm AC \ Code
AC Code
#include<bits/stdc++.h>
#define maxn 50005
#define S 250
#define pb push_back
using namespace std;
int n,b[maxn],q,m[maxn<<2],k[maxn<<2],ans[maxn<<2];
vector<int>G[maxn];
int tr[maxn];
void upd(int u,int v){ for(;u<=n;u+=u&-u) tr[u]+=v; }
int qsum(int u){ int ret=0;for(;u;u-=u&-u) ret+=tr[u];return ret; }
struct young_tableaux{
int a[S][maxn],tp;
young_tableaux(){memset(a,0,sizeof a);tp=0;}
void ins(int u,int R,int x){
if(u>=S) return;
R = min(R,a[u][0]+1);
int L = 1 , mid;
for(;L<R;){
mid = (L+R) >> 1;
if(tp ^ (a[u][mid] < x)) R = mid;
else L = mid + 1;
}
swap(a[u][L],x),a[u][0]=max(a[u][0],L);
if(x) ins(u+1,L,x);
else{ if(tp==0) upd(u,1);
else if(L>=S) upd(L,1);}
}
}t0,t1;
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=q;i++) scanf("%d%d",&m[i],&k[i]),G[m[i]].pb(i);
t1.tp=1;
for(int i=1;i<=n;i++){
t0.ins(1,n,b[i]),t1.ins(1,n,b[i]);
for(int j=0;j<G[i].size();j++) ans[G[i][j]]=qsum(k[G[i][j]]);
}
for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
}