[BZOJ] 2131: 免费的馅饼

\(f[i]\)表示考虑了前\(i\)个馅饼且第\(i\)个必接的最大收益,先写出转移方程

\[f[i]=\max_{j合法}\{f[j]\}+w_i \]

\(j\)合法究竟意味着什么?

不难发现,就是 \(dis(i,j)\leq 速度\times (t[i]-t[j])\)

速度有1有2,很麻烦,所以我们把时间全部乘2,速度就是1了

现在判合法就简单了,可以写出清晰的式子

\[\mid x[j]-x[i]\mid \leq t[i]-t[j] \]

解出来

\[\begin{align*} t[j]+x[j]&\geq t[i]+x[i]\\ x[j]-t[j]&\leq x[i]-t[i] \end{align*} \]

二者是或的关系,这就是一个二维偏序问题

因此我们按\(t[i]+x[i]\)降序排序,用树状数组查询下标\(x[i]-t[i]\)前缀最小值,即可将方程优化到\(O(nlogn)\)

#include<algorithm>
#include<iostream>
#include<cstdio>

using namespace std;

inline int rd(){
  int ret=0,f=1;char c;
  while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
  while(isdigit(c))ret=ret*10+c-'0',c=getchar();
  return ret*f;
}
#define space() putchar(' ')
#define nextline() putchar('\n')
void pot(int x){if(!x)return;pot(x/10);putchar('0'+x%10);}
void out(int x){if(!x)putchar('0');if(x<0)putchar('-'),x=-x;pot(x);}

const int MAXN = 100005;

inline void upmax(int &x,int y){x=max(x,y);}

struct Node{
  int a,b,w;
  Node(int x=0,int y=0,int z=0){a=x;b=y;w=z;}
  bool operator<(const Node &rhs)const{
    return a>rhs.a;
  }
}node[MAXN];

int n,m;
int sav[MAXN];
int bit[MAXN];
int f[MAXN];
void update(int x,int w){
  for(int i=x;i<=n;i+=i&-i)upmax(bit[i],w);
}
int query(int x){
  int ret=0;
  for(int i=x;i;i-=i&-i)upmax(ret,bit[i]);
  return ret;
}
signed main(){
  m=rd();n=rd();
  int t,p,w;
  for(int i=1;i<=n;i++){
    t=rd();p=rd();w=rd();t<<=1;
    node[i]=Node(t+p,p-t,w);
    sav[i]=p-t;
  }
  sort(sav+1,sav+1+n);
  int tot=unique(sav+1,sav+1+n)-sav-1;
  for(int i=1;i<=n;i++){
    node[i].b=lower_bound(sav+1,sav+tot,node[i].b)-sav;
  }
  sort(node+1,node+1+n);
  int ans=0;
  for(int i=1;i<=n;i++){
    f[i]=query(node[i].b)+node[i].w;
    update(node[i].b,f[i]);
    upmax(ans,f[i]);
  }
  out(ans);
  return 0;
}

posted @ 2018-10-19 20:53  GhostCai  阅读(127)  评论(0编辑  收藏  举报