题目链接:https://www.luogu.com.cn/problem/P1020
题目大意:
Dilworth定理:偏序集能划分成的最少的全序集个数等于最大反链的元素个数。
例
如
对
于
(
a
[
i
]
,
b
[
]
)
和
(
a
[
j
]
,
b
[
j
]
)
这
两
个
元
素
,
如
果
我
们
定
义
偏
序
关
系
为
:
a
[
i
]
<
a
[
j
]
并
且
b
[
i
]
>
b
[
j
]
那
么
它
的
反
链
为
:
a
[
i
]
<
a
[
j
]
并
且
b
[
i
]
<
=
b
[
i
]
对
于
这
道
题
,
我
们
以
下
标
为
a
[
i
]
,
值
为
b
[
i
]
那
么
偏
序
关
系
为
:
a
[
i
]
<
a
[
j
]
并
且
b
[
i
]
>
=
b
[
j
]
反
链
为
:
a
[
i
]
<
a
[
j
]
并
且
b
[
i
]
<
b
[
j
]
全
序
集
最
大
大
小
为
:
最
长
不
上
升
子
序
列
最
长
反
链
为
:
最
长
上
升
子
序
列
\begin{array}{l} 例如对于(a[i], b[])和(a[j], b[j])这两个元素,如果我们定义偏序关系为:a[i]<a[j]并且b[i]>b[j] \\ 那么它的反链为:a[i]<a[j]并且b[i]<=b[i]\\ \\ 对于这道题,我们以下标为a[i], 值为b[i]\\ 那么偏序关系为:a[i]<a[j]并且b[i]>=b[j] \\ 反链为:a[i]<a[j]并且b[i]<b[j] \\ 全序集最大大小为:最长不上升子序列 \\ 最长反链为:最长上升子序列 \end{array}
例如对于(a[i],b[])和(a[j],b[j])这两个元素,如果我们定义偏序关系为:a[i]<a[j]并且b[i]>b[j]那么它的反链为:a[i]<a[j]并且b[i]<=b[i]对于这道题,我们以下标为a[i],值为b[i]那么偏序关系为:a[i]<a[j]并且b[i]>=b[j]反链为:a[i]<a[j]并且b[i]<b[j]全序集最大大小为:最长不上升子序列最长反链为:最长上升子序列
#include<bits/stdc++.h>
#define LL long long
using namespace std;
struct BitTree
{
int a[2][100005];
int lowbit(int x){
return x&(-x);
}
void update(int x,int d,int op){//a[x]=d//修改a[x]的权值只能增加 0:后缀最大值
if(op==0){
while(x){
a[0][x] = max(a[0][x],d);
x -= lowbit(x);
}
}
else{
while(x <= 100005){
a[1][x] = max(a[1][x],d);
x += lowbit(x);
}
}
}
int query(int x,int op){
int ret = -1e9;
if(op==0){
while(x <= 100005){
ret = max(a[0][x],ret);
x += lowbit(x);
}
}
else {
while(x){
ret = max(ret,a[1][x]);
x -= lowbit(x);
}
}
return ret;
}
}b;
int a[200005];
int main(){
int n=0, ans1=0, ans2=0;
while(scanf("%d", &a[++n])!=EOF);
n--;//读后才判断所以最后一个n没有读到数
for(int i=1; i<=n; i++){//最长不上升子序列
int m=b.query(a[i], 0);
ans1=max(ans1, m+1);
b.update(a[i], m+1, 0);
}
for(int i=1; i<=n; i++){//最长上升子序列
int m=b.query(a[i], 1);
ans2=max(ans2, m+1);
b.update(a[i]+1, m+1, 1);//a[i]+1是因为树状数组的下标最小为1
}
printf("%d\n%d\n", ans1, ans2);
return 0;
}