[洛谷1868]饥饿的奶牛
思路:
动态规划。
类似于线段覆盖,首先对每个区间的右端点从小到大排好序。
对于每个区间$s_i$,状态转移方程为$f_{s_i.r}=\max\limits_{0\leq j\leq s_i.l}\{f_j\}$。
对于这个$max$,我们可以用一个树状数组来维护前缀最大值。
有$n$组区间,区间范围是$0\sim m$,渐近时间复杂度为$O(n\log m)$。
另外注意区间有可能为$0$,用树状数组不好维护,因此我们可以将所有的端点$+1$。
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<algorithm> 5 inline int getint() { 6 char ch; 7 while(!isdigit(ch=getchar())); 8 int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=150000,M=3000002; 13 int m=0; 14 class FenwickTree { 15 private: 16 int val[M]; 17 int lowbit(const int x) { 18 return x&-x; 19 } 20 public: 21 FenwickTree() { 22 memset(val,0,sizeof val); 23 } 24 void modify(int p,const int x) { 25 while(p<=m) { 26 val[p]=std::max(val[p],x); 27 p+=lowbit(p); 28 } 29 } 30 int query(int p) { 31 int ret=0; 32 while(p) { 33 ret=std::max(ret,val[p]); 34 p-=lowbit(p); 35 } 36 return ret; 37 } 38 }; 39 FenwickTree t; 40 int f[M]={0}; 41 struct Segment { 42 int x,y; 43 bool operator < (const Segment &another) const { 44 return y<another.y; 45 } 46 }; 47 Segment s[N]; 48 int main() { 49 int n=getint(); 50 for(register int i=0;i<n;i++) { 51 s[i].x=getint()+1; 52 s[i].y=getint()+1; 53 m=std::max(m,s[i].y); 54 } 55 std::sort(&s[0],&s[n]); 56 int ans=0; 57 for(register int i=0;i<n;i++) { 58 int &x=s[i].x,&y=s[i].y; 59 int tmp=t.query(x-1)+y-x+1; 60 if(tmp>f[y]) { 61 t.modify(y,f[y]=tmp); 62 ans=std::max(ans,tmp); 63 } 64 } 65 printf("%d\n",ans); 66 return 0; 67 }