洛谷 P1020 导弹拦截 Dilworth定理

题目链接: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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值