[分塊] Codeforces 436F Zepto Code Rush 2014 F. Banners

可以轉化成區間加,詢問ai×i 的最大值
這個不好維護,分塊,零散的加,直接重構整塊,否則在塊上打標記
同時我們在塊上還要維護當前最大值所在的 i 和 接下來至少要整塊加多少次才能使得最大值變化
每次在塊上打標記,當達到臨近就重構更新最大值,注意這個最大值隨着全局加肯定是單調右移的,那麼重構複雜度也是對的

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章