可以转化成区间加,询问
ai×i
的最大值
这个不好维护,分块,零散的加,直接重构整块,否则在块上打标记
同时我们在块上还要维护当前最大值所在的
i
<script type="math/tex" id="MathJax-Element-121">i</script> 和 接下来至少要整块加多少次才能使得最大值变化
每次在块上打标记,当达到临近就重构更新最大值,注意这个最大值随着全局加肯定是单调右移的,那么重构复杂度也是对的
#include<cstdio>
#include<cstdlib>
#include<cassert>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
int n,W;
int a[N],b[N];
int maxa=0;
int idx[N];
inline bool cmp(int x,int y){
return b[x]<b[y];
}
const int BB=505;
int B,cnt;
int pos[N];
int lp[BB],rp[BB];
ll c[N];
int tag[BB]; ll clk[BB]; int K[BB];
inline void Build(){
B=(int)sqrt(maxa);
for (int i=0;i<=maxa;i++) pos[i]=i/B+1; cnt=pos[maxa];
for (int i=1;i<=cnt;i++) lp[i]=(i-1)*B,rp[i]=i*B-1; rp[cnt]=maxa;
for (int i=1;i<=cnt;i++){
K[i]=lp[i]; if (K[i]==rp[i]) clk[i]=1<<30; else clk[i]=1;
}
}
inline void rebuild(int x,int l,int r){
ll maxv=-1,k=0,t=0;
for (int i=lp[x];i<=rp[x];i++){
c[i]+=tag[x];
c[i]+=(l<=i && i<=r);
if (c[i]*i>maxv) maxv=c[i]*i,k=i;
}
K[x]=k; tag[x]=0;
clk[x]=1<<30;
for (int i=k+1;i<=rp[x];i++)
clk[x]=min(clk[x],(c[k]*k-c[i]*i)/(i-k)+1);
}
inline void Add(int r){
int rb=pos[r];
rebuild(rb,lp[rb],r);
for (int i=1;i<rb;i++){
tag[i]++; clk[i]--;
if (!clk[i]) rebuild(i,0,-1);
}
}
ll ans=0,p;
inline void Query(){
ans=0; p=0;
for (int i=1;i<=cnt;i++)
if ((c[K[i]]+tag[i])*K[i]>ans)
ans=(c[K[i]]+tag[i])*K[i],p=K[i];
}
int main(){
freopen("deep.in","r",stdin);
freopen("deep.out","w",stdout);
read(n); read(W);
for (int i=1;i<=n;i++) read(a[i]),read(b[i]),idx[i]=i,maxa=max(maxa,a[i]);
Build();
sort(idx+1,idx+n+1,cmp);
int lim=b[idx[n]]+1,pnt=1;
for (int c=0;c<=lim;c++){
while (pnt<=n && c>b[idx[pnt]])
Add(a[idx[pnt]]),pnt++;
Query();
printf("%lld %d\n",(ll)c*W*(n-pnt+1)+ans,p);
}
return 0;
}