首先把所有的用户按b升序排序,从小到大枚举c,每次广告的收入是可以直接计算出来的,我们只需要确定一个p,使得p∗(ai>=p的个数)最大。不难发现,p一定可以等于某个ai时取得最优。因此我们按ai分块,每一块维护一个下凸壳,记块内的最优位置。每次求最优时就对所有块的最优位置算一个答案然后取max。
记d[i]表示p=i时的答案,每次往里加一个点x时,对d的影响是:d[1]+=1,…d[x]+=x。对于一整块都加的,我们直接对每一块维护一个cnt,而不加进去,通过下凸壳来找到最优位置。
如果i<j,d[i]>d[j],d[i]+i∗cnt<=d[j]+j∗cnt,
则有(d[i]−d[j])/(j−i)<=cnt。因此我们要维护斜率单增的单调队列,也就是下凸壳。
对于不是一整块都加的,我们暴力重构这个块的凸包。每个数最多重构一块,所以重构的复杂度是O(nn√)的。
总的复杂度也就是O(nn√)
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 100010
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}\
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,w,mxb,mxa,bel[N],nn,cnt[350],q[350][350],qh[350],qt[350];
ll d[N];
struct data{
int a,b;
friend bool operator<(data a,data b){return a.b<b.b;}
}A[N];
inline double slope(int i,int j){return (d[i]-d[j])*1.0/(j-i);}
inline void gao(int i,int x){
while(qh[i]<qt[i]&&slope(q[i][qh[i]],q[i][qh[i]+1])<=x) ++qh[i];
}
inline void rebuild(int id,int l,int r){
qh[id]=1;qt[id]=0;
for(int i=l;i<=r;++i){
while(qh[id]<qt[id]&&slope(q[id][qt[id]],i)<slope(q[id][qt[id]-1],q[id][qt[id]])) --qt[id];
q[id][++qt[id]]=i;
}gao(id,0);
}
inline void add(int x){
if(!x) return;
for(int i=1;i<bel[x];++i) gao(i,++cnt[i]);
int l=(bel[x]-1)*nn+1,r=min(bel[x]*nn,mxa),id=bel[x];
for(int i=l;i<=r;++i) d[i]+=(ll)cnt[id]*i;
for(int i=l;i<=x;++i) d[i]+=i;cnt[id]=0;rebuild(id,l,r);
}
int main(){
// freopen("a.in","r",stdin);
n=read();w=read();
for(int i=1;i<=n;++i) A[i].a=read(),A[i].b=read(),mxb=max(mxb,A[i].b),mxa=max(mxa,A[i].a);
sort(A+1,A+n+1);int now=1;nn=sqrt(mxa);
for(int i=1;i<=mxa;++i) bel[i]=(i-1)/nn+1;int tot=bel[mxa];
for(int i=1;i<=tot;++i) qh[i]=1,q[i][++qt[i]]=min(i*nn,mxa);int flag=0;
for(int c=0;c<=mxb+1;++c){
while(now<=n&&A[now].b<c) add(A[now].a),++now;
ll ans=0;int ans1=0;
for(int i=1;i<=tot;++i){int x=q[i][qh[i]];if(d[x]+(ll)x*cnt[i]>ans) ans=d[x]+(ll)x*cnt[i],ans1=x;}
printf("%I64d %d\n",ans+(ll)w*c*(n-now+1),ans1);if(c==1) flag=ans+(ll)w*c*(n-now+1);
}return 0;
}