篱莘龙 题解

题面

今天联赛T2,并没想到做法。

从特殊性质入手,当有 \(a_i<b_i\) 时,把每个奶龙看作区间 \([a_i,b_i]\),互不攻击当且仅当所有选中的区间有交点。则用一个线段树维护区间加和区间最大值即可。

当 \(a_i>b_i\) 时,区间是 \([b_i,a_i]\),此时 \(a_i<b_j\) 且 \(a_j<b_i\) 矛盾,最多只能选 \(1\) 个。

考虑两种都有的情况,还是用一棵线段树维护区间最大值,如果要选一个 \([b_x,a_x]\),则要求一个普通奶龙的 \([a_i,b_i]\) 完全覆盖这个区间,而且它不能和任何普通奶龙的区间是不完全的覆盖,我们引入另外一棵线段树,支持单点修,区间查最小值及其位置,我们把每个特殊奶龙存在线段树其右端点的位置上,值为左端点。每一次加入一个新的普通奶龙时,他可能会和原有的特殊奶龙相交,我们就把这些特殊奶龙都删除掉,包括其在线段树 \(1\) 中单点的贡献。

当加入的是一个特殊奶龙,我们需要事先判断它是否已经和普通区间有交了,可以用一个树状数组,每一个位置存有几个端点,区间查即可。如果合法,就把 sgt2 的右端点位置赋值为左端点的值,把 sgt1 的右端点单点加上 \(1\)。

复杂度 \(O(n\log n)\)。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int T,o,n,k;
const int N = 1e6+10,inf=1e18;
int a[N],b[N];
int mx[N<<3],tag[N<<3];
struct node{
    int mi,id;
}tr[N<<3];
set<int>s;
#define ls p<<1
#define rs p<<1|1
struct sgt1{
    void pushup(int p){
        mx[p]=max(mx[ls],mx[rs]);
    }
    void pushdown(int p){
        if(tag[p]){
            mx[ls]+=tag[p];mx[rs]+=tag[p];
            tag[ls]+=tag[p];tag[rs]+=tag[p];
            tag[p]=0;
        }
    }
    void modify(int p,int l,int r,int ql,int qr,int v){
        if(ql>qr)return;
        if(ql<=l&&r<=qr){
            mx[p]+=v;
            tag[p]+=v;
            return;
        }
        pushdown(p);
        int mid=(l+r)/2;
        if(ql<=mid)modify(ls,l,mid,ql,qr,v);
        if(qr>mid)modify(rs,mid+1,r,ql,qr,v);
        pushup(p);
    }
}T1;
struct sgt2{
    #define mi(p) tr[p].mi
    #define id(p) tr[p].id
    void pushup(int p){
        if(mi(ls)<mi(rs))tr[p]=tr[ls];
        else tr[p]=tr[rs];
    }
    void build(int p,int l,int r){
        if(l==r){
            id(p)=l;
            mi(p)=inf;
            return;
        }
        int mid=(l+r)/2;
        build(ls,l,mid);build(rs,mid+1,r);
        pushup(p);
    }
    void add(int p,int l,int r,int x,int v){
        if(l==r){
            mi(p)=v;
            return;
        }
        int mid=(l+r)/2;
        if(x<=mid)add(ls,l,mid,x,v);
        else add(rs,mid+1,r,x,v);
        pushup(p);
    }
    node query(int p,int l,int r,int ql,int qr){
        if(ql<=l&&r<=qr){
            return tr[p];
        }
        int mid=(l+r)/2;
        if(qr<=mid)return query(ls,l,mid,ql,qr);
        if(ql>mid)return query(rs,mid+1,r,ql,qr);
        node lt=query(ls,l,mid,ql,qr),rt=query(rs,mid+1,r,ql,qr);
        if(lt.mi<rt.mi)return lt;
        else return rt;
    }
}T2;
int lowbit(int x){
    return x&(-x);
}
struct bit{
    int t[N<<1];
    void add(int p,int v){
        for(int i=p;i<=2*n;i+=lowbit(i))t[i]+=v;
    }
    int ask(int p){
        int res=0;
        for(int i=p;i;i-=lowbit(i)){
            res+=t[i];
        }
        return res;
    }
}t3;
void solve(int x){
    t3.add(x,1);
    while(1){
        node t=T2.query(1,1,2*n,x,2*n);
        if(t.mi>=x)return;
        T2.add(1,1,2*n,t.id,inf);
        T1.modify(1,1,2*n,t.id,t.id,-1);
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i]>>b[i];
    }
    T2.build(1,1,2*n);
    for(int i=1;i<=n;i++){
        if(a[i]<=b[i]){
            solve(a[i]);solve(b[i]);
            T1.modify(1,1,2*n,a[i],b[i],1);
        }else{
            if(t3.ask(a[i])-t3.ask(b[i]-1)>0){
                cout<<mx[1]<<endl;
                continue;
            }
            T2.add(1,1,2*n,a[i],b[i]);
            T1.modify(1,1,2*n,a[i],a[i],1);
        }
        cout<<mx[1]<<endl;
    }
    return 0;
}
posted @ 2026-09-26 17:55  farenara_sayowell  阅读(3)  评论(0)    收藏  举报