可以轉化成區間加,詢問
這個不好維護,分塊,零散的加,直接重構整塊,否則在塊上打標記
同時我們在塊上還要維護當前最大值所在的
每次在塊上打標記,當達到臨近就重構更新最大值,注意這個最大值隨着全局加肯定是單調右移的,那麼重構複雜度也是對的
#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;
}