吐槽

看这道题的时候,由于英语太菜
读题读了好久都没读懂
依据暂时的理解打了一个程序之后发现一直WA
最后在玄学注释(去掉排序)程序的时候,居然A了。。。
之后在机房英语巨佬シンドリー的帮助下才懂得了题意。。。

分析

不太懂题意的,可以看看这位巨佬的Blog
一眼题?(以前在Atcoder上边好像做过类似的题)
我们需要的是按照题目给定的序列顺序找出其中的几段
能够使得每两端之间有至少一个交点的情况下覆盖整段序列
我们设DP[i]表示覆盖完所需要的最小段数
所以我们可以得到DP方程

发现,这个状态转移是一个区间最小值的转移
所以我们直接上线段树优化DP即可

代码

//POJ 1769
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

#define LL long long
#define Cl(X,Y) memset((X),(Y),sizeof(X))
#define FOR(i,A,B) for(LL i=A;i<=B;i++)
#define BOR(i,A,B) for(LL i=A;i>=B;i--)
#define Lowbit(X) (X & (-X))
#define Skip cout<<endl;
#define INF 0x3f3f3f3f3f3f3f3f
#define Rson (X<<1|1)
#define Lson (X<<1)
using namespace std;
const LL MaxM=5e5+10;

LL Total,Range;
struct Node {
    LL From,To;
    friend bool operator < (Node A,Node B) {
        if(A.To!=B.To) return A.To<B.To;
        else return A.From<B.From;
    }
}Line[MaxM];
LL DP[MaxM],Loc,Max;
LL Min[MaxM<<2];

inline void File() {
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
}

inline void Push_up(LL X) { Min[X]=min(Min[Lson],Min[Rson]); }
inline void Update(LL X,LL L,LL R,LL Loc,LL Temp) {
    if(L==R) { Min[X]=min(Min[X],Temp); return; }
    LL Mid=(L+R)>>1;
    if(Loc<=Mid) { Update(Lson,L,Mid,Loc,Temp); }
    else { Update(Rson,Mid+1,R,Loc,Temp); }
    Push_up(X);
}

inline LL Get(LL X,LL L,LL R,LL From,LL To) {
    if(L>=From && R<=To) { return Min[X]; }
    LL Mid=(L+R)>>1,Res=INF;
    if(From<=Mid) { Res=min(Res,Get(Lson,L,Mid,From,To)); }
    if(To>Mid) { Res=min(Res,Get(Rson,Mid+1,R,From,To)); }
    Push_up(X);
    return Res;
}

signed main() {
    // File();
    // ios::sync_with_stdio(false);
    scanf("%lld %lld",&Total,&Range);
    // cin>>Total>>Range;
    Cl(Min,0x3f); Cl(DP,0x3f);          
    FOR(i,1,Range) scanf("%lld %lld",&Line[i].From,&Line[i].To);
    // sort(Line+1,Line+Range+1);
    Update(1,1,Total,1,0);  
    FOR(i,1,Range) {
        LL Temp=Get(1,1,Total,Line[i].From,Line[i].To-1);
        DP[Line[i].To]=min(DP[Line[i].To],Temp+1);
        Update(1,1,Total,Line[i].To,DP[Line[i].To]);
    }
    cout<<Get(1,1,Total,Total,Total)<<endl;
    // fclose(stdin);
    // fclose(stdout);
    system("pause");
    return 0;
}