Atcoder [ABC410G] Longest Chord Chain 题解 [ 蓝 ] [ 线段树优化 DP ]

Longest Chord Chain:又简单又典的题。

首先断环为链,把所有弦放在一根直线上考虑,这是显然的。

那么两条弦相交,当且仅当他们在直线上不是相互独立或者相互包含的关系

接下来考虑转化选择的限制:

  • 所有弦不能相交 \(\to\) 直线上的关系只能是相互独立或者相互包含。
  • 选择一根线穿过选择的弦 \(\to\) 一条弦不能同时穿过相互独立的另外两条弦,所以相当于只能穿过相互包含的弦。

因此,问题被转化为直线上最多有多少条弦是相互嵌套、包含的关系。

于是设计线性 DP:\(dp_i\) 表示以 \(i\) 为最外侧右端点的答案。因为所有弦的端点互不相同,所以每个点都只用转移一次。假设前驱端点为 \(pre\),那么只要查询最外层左端点在 \([pre+1,i-1]\) 之间的最大值就可以转移了。这是个二维偏序问题,而又因为我们的 \(i\) 是从小到大枚举的,上界限制显然满足,所以直接查询最外层左端点大于 \(pre\) 的最大值即可。采用线段树或树状数组实现,时间复杂度 \(O(n\log n)\)

或者还可以把它转化为 LIS 问题:将相互包含的弦按左端点排序,右端点的 LIS 即为答案。

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=800005;
int n,pre[N],dp[N],ans;
struct Node{
    int l,r,v;
};
struct Segtree{
    Node tr[4*N];
    void pushup(int p)
    {
        tr[p].v=max(tr[lc].v,tr[rc].v);
    }
    void build(int p,int ln,int rn)
    {
        tr[p]={ln,rn,0};
        if(ln==rn)return;
        int mid=(ln+rn)>>1;
        build(lc,ln,mid);
        build(rc,mid+1,rn);
        pushup(p);
    }
    void update(int p,int x,int v)
    {
        if(tr[p].l==x&&tr[p].r==x)
        {
            tr[p].v=v;
            return;
        }
        int mid=(tr[p].l+tr[p].r)>>1;
        if(x<=mid)update(lc,x,v);
        else update(rc,x,v);
        pushup(p);
    }
    int query(int p,int ln,int rn)
    {
        if(ln<=tr[p].l&&tr[p].r<=rn)return tr[p].v;
        int mid=(tr[p].l+tr[p].r)>>1;
        if(rn<=mid)return query(lc,ln,rn);
        if(ln>=mid+1)return query(rc,ln,rn);
        return max(query(lc,ln,rn),query(rc,ln,rn));
    }
}tr1;
int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        int a,b;
        cin>>a>>b;
        if(a>b)swap(a,b);
        pre[b]=a;
        pre[b+2*n]=a+2*n;
        pre[a+2*n]=b;
    }
    tr1.build(1,1,4*n);
    for(int i=1;i<=4*n;i++)
    {
        if(pre[i]==0)continue;
        dp[i]=tr1.query(1,pre[i]+1,i)+1;
        tr1.update(1,pre[i],dp[i]);
        ans=max(ans,dp[i]);
    }
    cout<<ans;
    return 0;
}
posted @ 2025-06-16 00:23  KS_Fszha  阅读(24)  评论(0)    收藏  举报