文章目录

题解:P13520 [KOI 2025 #2] 存放箱子

由 SunJude 发布

首先 $i$ 能嵌套到 $j$ 里当且仅当 $c_i < s_i \leq c_j < s_j$,这是一个偏序的关系。把嵌套关系视作链,在一条链上的都满足偏序关系,则我们要求的就是覆盖整个集合所需的最少链的条数。

根据 Dilworth 定理最小链覆盖等于最长反链,于是转化成求一个最大的集合,其中任意两个元素均不满足偏序关系,也就是 $c_i < c_j \land s_i > s_j$ 或 $c_i > c_j \land s_i < s_j$。考虑把这些点画到数轴上,元素 $i$ 就可以用线段 $[c_i, s_i)$ 表示,则两个元素不满足偏序关系当且仅当两条线段有交。于是这个集合中的线段两两有交,并且显然会交于同一点。

那我们维护每个点被线段覆盖的次数即可。具体地,插入一个线段就是对 $[c_i, s_i - 1]$ 区间 $+1$,并查询全局最大值。

直接离散化之后用线段树维护即可。

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long 
#define pii pair<int,int>
#define pb push_back
#define eb emplace_back
#define endl '\n'
#define rep(i, a, b) for(int (i) = (a); (i) <= (b); (i) ++)
#define per(i, a, b) for(int (i) = (a); (i) >= (b); (i) --)
#define REP(i, l, r, k) for (int i = (l); i <= (r); i += k)
#define PER(i, l, r, k) for (int i = (l); i >= (r); i -= k)
#define ls x << 1
#define rs x << 1 | 1
#define umap unordered_map
#define uset unordered_set
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define vi vector<int>
#define x1 Sun
#define y1 Jude
void ckmin(int &x, int y) { x = std::min(x, y) ; }
void ckmax(int &x, int y) { x = std::max(x, y) ; }
int lowbit(int x) { return x & -x ; }

using namespace std;

const int maxn = 4e5 + 5 ;
// const int inf = ;
// const int mod = ; 

int n, s[maxn], c[maxn] ; 

struct sgt {
    int l[maxn << 2], r[maxn << 2] ; 
    int mx[maxn << 2], tag[maxn << 2] ;
    void Add(int x, int k) { mx[x] += k, tag[x] += k ; }
    void pushup(int x) { mx[x] = max(mx[ls], mx[rs]) ; }
    void pushdown(int x) {
        if(!tag[x]) return ; 
        Add(ls, tag[x]) ; Add(rs, tag[x]) ;  
        tag[x] = 0 ; 
    }
    void build(int x, int L, int R) {
        l[x] = L, r[x] = R  ;
        if(L == R) return ;
        int mid = (L + R) >> 1 ;  
        build(ls, L, mid) ;  
        build(rs, mid + 1, R) ; 
    }
    void add(int x, int L, int R, int k) {
        if(L <= l[x] && r[x] <= R) {
            Add(x, k) ;  
            return ; 
        }
        pushdown(x) ;
        int mid = (l[x] + r[x]) >> 1 ; 
        if(L <= mid) add(ls, L, R, k) ;
        if(R > mid) add(rs, L, R, k) ; 
        pushup(x) ;
    }
} t ;

vector<int> node ; 

void solve(){
    cin >> n ; 
    rep(i, 1, n) {
        cin >> s[i] >> c[i] ;
        node.pb(s[i]) ; node.pb(c[i]) ; 
    }
    sort(all(node)) ;
    node.erase(unique(all(node)), node.end()) ;
    int N = node.size() ;
    t.build(1, 0, N - 1) ; 
    rep(i, 1, n) {
        int ss = lower_bound(all(node), s[i]) - node.begin(), cc = lower_bound(all(node), c[i]) - node.begin() ; 
        if(cc <= ss - 1) t.add(1, cc, ss - 1, 1) ; 
        cout << t.mx[1] << endl ;
    }
    return ;
}
signed main(){
    // freopen("box.in", "r", stdin) ; 
    // freopen("box.out", "w", stdout) ; 
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T = 1 ; 
//  cin >> T ;
    while(T -- ){
        solve() ;
    }
    return 0 ;
}

暂无评论

发表评论