问题
分析
dp[i]代表覆盖了[1,i]区间的最小代价
状态
线段树,单点更新,区间查询
#include<iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
const int maxn=50000+5,INF=0x3f3f3f3f;
//使用线段树,单点更新,求区间最小值
struct Tree{
int left,right,minv;
Tree(int left=0,int right=0,int minv=0):left(left),right(right),minv(minv){}
}tree[maxn*4];
int dp[maxn],kase,n,m,l,r;
void pushup(int rt){
tree[rt].minv=min(tree[rt<<1].minv,tree[rt<<1|1].minv);
}
//建树
void build(int rt,int left,int right){
tree[rt].left=left,tree[rt].right=right;
if(left==right){
tree[rt].minv=INF;
return;
}
int mid=(left+right)>>1;
build(rt<<1,left,mid);
build(rt<<1|1,mid+1,right);
pushup(rt);
}
//更新一个点pos的值v,[left,right]=[tree[rt].left,tree[rt].right]
void update(int rt,int left,int right,int pos,int v){
if(left==right){
tree[rt].minv=v;
return;
}
int mid=(left+right)>>1;
if(pos<=mid) update(rt<<1,left,mid,pos,v);
else update(rt<<1|1,mid+1,right,pos,v);
pushup(rt); //别忘了向上更新
}
int query(int rt,int left,int right,int LEFT,int RIGHT){
if(LEFT<=left && RIGHT>=right){ //如果这个区间被完全包围
return tree[rt].minv;
}
int mid=(left+right)>>1,t1=INF,t2=INF;
if(LEFT<=mid) t1=query(rt<<1,left,mid,LEFT,RIGHT);
if(RIGHT>mid) t2=query(rt<<1|1,mid+1,right,LEFT,RIGHT);
return min(t1,t2);
}
int main(void){
cin>>kase;
while(kase--){
scanf("%d%d",&n,&m);
memset(dp,INF,sizeof(dp));
build(1,1,n);
dp[1]=0;
update(1,1,n,1,0);
for(int i=0;i<m;++i){
scanf("%d%d",&l,&r);
int t=query(1,1,n,l,r); //查询[l,r]中的最小值
if(t+1<dp[r]){
dp[r]=t+1; //更新
update(1,1,n,r,t+1); //更新dp[r]
}
}
printf("%d\n",dp[n]);
if(kase) printf("\n");
}
return 0;
}