洛谷 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}

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章