zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 92 (Rated for Div. 2) 选讲

    https://codeforces.ml/contest/1389/problem/F

    法一:dp,所有区间按右端点排序,依次考虑“如果最后一个区间为该区间”的最优情况,它(叫做A)可以从一个“右端点比A的左端点小”的异类区间B转移过来,但是同时可以顺便把“B的右端点以右”的同类区间算上。算上同类区间可以用线段树维护:每次计算完一个区间[L,R]后,把右端点小于L的所有异类区间的dp值+1。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long
     4  
     5 int n;
     6 const int maxn=400011;
     7  
     8 struct SEG
     9 {
    10     int l,r,t;
    11     bool operator < (const SEG &b) const
    12     {
    13         return r<b.r;
    14     }
    15 }seg[maxn];
    16 int lisa[maxn<<1],li=0;
    17  
    18 int dp[maxn],contain[maxn];
    19 struct SmtNode{int Max,add;};
    20 struct SMT
    21 {
    22     SmtNode a[maxn<<2];
    23     int n;
    24     SMT() {n=0;}
    25     void clear(int N) {n=N;}
    26 //    int ls(int x) {return x<<1;}
    27 //    int rs(int x) {return (x<<1)|1;}
    28     #define ls(x) (x<<1)
    29     #define rs(x) ((x<<1)|1)
    30     void up(int x) {a[x].Max=max(a[ls(x)].Max,a[rs(x)].Max);}
    31     void addsingle(int x,int v) {a[x].Max+=v; a[x].add+=v;}
    32     void down(int x) {if (a[x].add>0) {addsingle(ls(x),a[x].add); addsingle(rs(x),a[x].add); a[x].add=0;} }
    33     void Insert(int x,int L,int R,int p,int v)
    34     {
    35         if (L==R) {a[x].Max=max(a[x].Max,v); return;}
    36         down(x);
    37         int mid=(L+R)>>1;
    38         if (p<=mid) Insert(ls(x),L,mid,p,v);
    39         else Insert(rs(x),mid+1,R,p,v);
    40         up(x);
    41     }
    42     void insert(int p,int v) {Insert(1,0,n,p,v);}
    43     int QPreMax(int x,int L,int R,int p)
    44     {
    45         if (R<=p) return a[x].Max;
    46         down(x);
    47         int mid=(L+R)>>1;
    48         if (p<=mid) return QPreMax(ls(x),L,mid,p);
    49         return max(QPreMax(ls(x),L,mid,p),QPreMax(rs(x),mid+1,R,p));
    50     }
    51     int qPreMax(int p) {return QPreMax(1,0,n,p);}
    52     void Add(int x,int L,int R,int ql,int qr,int v)
    53     {
    54         if (ql<=L && R<=qr) {addsingle(x,v); return;}
    55         down(x);
    56         int mid=(L+R)>>1;
    57         if (ql<=mid) Add(ls(x),L,mid,ql,qr,v);
    58         if (qr>mid) Add(rs(x),mid+1,R,ql,qr,v);
    59         up(x);
    60     }
    61     void add(int L,int R,int v) {if (L<=R) Add(1,0,n,L,R,v);}
    62 }s[2];
    63  
    64 int main()
    65 {
    66     scanf("%d",&n);
    67     for (int i=1;i<=n;i++)
    68     {
    69         scanf("%d%d%d",&seg[i].l,&seg[i].r,&seg[i].t);
    70         seg[i].t--;
    71         lisa[++li]=seg[i].l;
    72         lisa[++li]=seg[i].r;
    73     }
    74     sort(lisa+1,lisa+1+li); li=unique(lisa+1,lisa+1+li)-lisa-1;
    75     for (int i=1;i<=n;i++)
    76     {
    77         seg[i].l=lower_bound(lisa+1,lisa+1+li,seg[i].l)-lisa;
    78         seg[i].r=lower_bound(lisa+1,lisa+1+li,seg[i].r)-lisa;
    79     }
    80     sort(seg+1,seg+1+n);
    81 //    for (int i=1;i<=n;i++) cout<<"NO"<<i<<' '<<seg[i].l<<' '<<seg[i].r<<' '<<seg[i].t<<endl;
    82     
    83     s[0].clear(li); s[1].clear(li);
    84     dp[0]=0;
    85     for (int i=1;i<=n;i++)
    86     {
    87         bool ty=seg[i].t;
    88         dp[i]=s[ty^1].qPreMax(seg[i].l-1)+1;
    89         s[ty].insert(seg[i].r,dp[i]);
    90         s[ty^1].add(0,seg[i].l-1,1);
    91 //        cout<<i<<' '<<dp[i]<<endl;
    92     }
    93     
    94     int ans=0;
    95     for (int i=1;i<=n;i++) ans=max(ans,dp[i]);
    96     printf("%d
    ",ans);
    97     return 0;
    98 }
    View Code

    法二:每个区间看作一个结点,会冲突的区间都连一条边,会形成一个二分图,目标是找最大独立集,转换为找最大匹配。复杂度不允许用二分图的算法。可将1类的区间按右端点升序,依次考虑能否匹配,对每个1类区间A,在所有能与之匹配的2类区间中贪心找右端点最小的即可。(枚举1类区间A的过程中会将“左端点小于A的右端点”的2类区间的右端点不停地丢入数据结构中,我们希望数据结构中存留下来的这些“右端点”们尽可能大,才能满足后面更大的“1类区间的左端点”)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long
     4 
     5 int n;
     6 struct SEG{int l,r;};
     7 vector<SEG> seg[2];
     8 multiset<int> s;
     9 
    10 int main()
    11 {
    12     scanf("%d",&n);
    13     for (int i=1,l,r,t;i<=n;i++)
    14     {
    15         scanf("%d%d%d",&l,&r,&t);
    16         seg[t-1].push_back((SEG){l,r});
    17     }
    18     sort(seg[0].begin(),seg[0].end(),[](SEG a,SEG b) {return a.r<b.r;});
    19     sort(seg[1].begin(),seg[1].end(),[](SEG a,SEG b) {return a.l<b.l;});
    20     
    21 //    cout<<endl;
    22     unsigned int j=0,ans=n;
    23     for (SEG x:seg[0])
    24     {
    25         while (j<seg[1].size() && seg[1][j].l<=x.r) s.insert(seg[1][j].r),j++;
    26         auto it=s.lower_bound(x.l);
    27         if (it==s.end()) continue;
    28 //        cout<<x.l<<' '<<x.r<<' '<<*it<<endl;
    29         s.erase(it);
    30         ans--;
    31     }
    32     printf("%d
    ",ans);
    33     return 0;
    34 }
    View Code
  • 相关阅读:
    BiliBili, ACFun… And More!【递归算法】
    【VS2015】关于VS2015如何运行的问题
    【打死树莓派】-树莓派3代jessie+Opencv-解决安装不了libgtk2.0-dev包问题
    插入排序2.0
    【C++小白成长撸】--(续)单偶数N阶魔方矩阵
    【C++小白成长撸】--(续)双偶数N阶魔阵
    安装 python-opencv
    二叉树打印
    Kotlin接口
    Kotlin 继承
  • 原文地址:https://www.cnblogs.com/Blue233333/p/13430868.html
Copyright © 2011-2022 走看看