AtCoder Regular Contest 126 B - Cross-free Matching (dp,线段树)

AtCoder Regular Contest 126  B - Cross-free Matching  (dp,线段树)

  • 题意:有2行,每行\(n\)个点,给你\(m\)个连接上下两行的边,问你最对能选多少条边,这些边互不相交。

  • 题解:先固定选上面或者下面一行作为起点去遍历,假设选下面一行,我们从头开始遍历,假设遍历到\(i\)个点时,枚举它的所有出边\(to\),假设这条边的终点为\(j\),设\(dp[j]\)表示区间\([1,j]\)的最多方案数,那么当前的状态一定为\(dp[j]=max(dp[j],dp[j-1]+1\)),因为\(dp\)数组表示的是区间最大值,所以可以用线段树来写,简单易懂。举个例子吧,比如有\(10\)个点,我们在\(dp[5]\)的位置更新了最大值,下一个位置是\(8\),我们要看\(dp[7]\)的值,但这\([6,7]\)这一段是空的,我们无法更新\(dp[8]\)的值,因为此时我们要看区间\([1,7]\)的最大值,这很明显是线段树嘛。。。。

  • 代码

    #include <iostream>
    #include <iomanip>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <stack>
    #include <queue>
    #include <vector>
    #include <map>
    #include <set>
    #include <unordered_set>
    #include <unordered_map>
    #define ll long long
    #define db double
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    int gcd(int a,int b){return b?gcd(b,a%b):a;}
    int lcm(int a,int b){return a/gcd(a,b)*b;}
    
    int n,m;
    PII pt[N];
    int dp[N];
    vector<int> edge[N];
    struct tree { int l, r, dat; }t[N << 4];
    
    inline int ls(int p) { return p << 1; }
    inline int rs(int p) { return ((p << 1) | 1); }
    
    inline void build(int p, int l, int r) {
        t[p].l = l, t[p].r = r;
        if (l == r) { t[p].dat = dp[l]; return ; }
        int mid = (l + r) >> 1;
        build(ls(p), l, mid);
        build(rs(p), mid + 1, r);
        t[p].dat = max(t[ls(p)].dat, t[rs(p)].dat);
    }
    
    inline void change(int p, int x, int v) {
        if (t[p].l == t[p].r) { t[p].dat = v; return ; }
        int mid = (t[p].l + t[p].r) >> 1;
        if (x <= mid) change(ls(p), x, v);
        else change(rs(p), x, v);
        t[p].dat = max(t[ls(p)].dat, t[rs(p)].dat);
    }
    
    
    inline int ask(int p, int l, int r) {
        if (l <= t[p].l && r >= t[p].r) return t[p].dat;
        int mid = (t[p].l + t[p].r) >> 1;
        int val = -INF;
        if (l <= mid) val = max(val, ask(ls(p), l, r));
        if (r > mid) val = max(val, ask(rs(p), l, r));
        return val;
    }
    
    int main() {
        scanf("%d %d",&n,&m);
        build(1,0,N);
        for(int i=1;i<=m;++i){
            scanf("%d %d",&pt[i].fi,&pt[i].se);
            edge[pt[i].fi].pb(pt[i].se);
        }
        int ans=0;
        for(int i=1;i<=n;++i){
            sort(edge[i].begin(),edge[i].end(),greater<int>());
            for(auto to:edge[i]){
                int now=ask(1,0,to-1);
                if(now+1>dp[to]){
                    dp[to]=now+1;
                    change(1,to,now+1);
                }
                ans=max(ans,dp[to]);
            }
        }
        printf("%d\n",ans);
        return 0;
    }
    
上一篇:【题解】AGC030F Permutation and Minimum


下一篇:AtCoder Grand Contest 008