[洛谷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 }

 

posted @ 2017-08-17 14:58  skylee03  阅读(205)  评论(0编辑  收藏  举报