题意大概是
有一个博客,初始赞数为0,每个人会浏览这篇博客,如果这个人期望的赞数大于这边博客的赞数,他就会赞这篇博客,如果小于这篇博客,就踩一下(博客赞数-1),相同就不操作。询问对于每个i,1~i的人按照一个顺序浏览,求一种顺序使得博客最后的赞数最大,输出这个最大的赞数。
先瞎猜一下,这1~i个人肯定是按照期望的赞数升序访问最优。
然后写个暴力交一下,发现T了,说明这个结论是对的
那么只要维护一下这个序列就可以了。可以用权值线段树维护。
考虑怎么求这个按照这个升序顺序访问能得到的答案。
首先
ai
(
ai
是当前排序后的数列中的第i个,不是原始数列的)是可能有负数的,那么肯定存在某个
x
,使
用
f(i)
表示在
i
位置博客的赞数,那么
展开展开展开发现一个区间
[l,r]
,长度为
k
那么每个区间维护一下 min(al+k−1,al+1+k−2,......,ar−1+1,ar) 就好了
#include <cstdio>
#include <iostream>
#include <algorithm>
#define N 500010
using namespace std;
typedef pair<int,int> parii;
int n;
int a[N];
parii b[N];
struct func{
int mn,tot;
int val(int x){
return min(x+tot,mn);
}
friend func operator *(func a,func b){
a.tot+=b.tot;
a.mn=min(b.mn,a.mn+b.tot);
return a;
}
};
struct seg{
int l,r,mx;
func f;
}T[N<<3];
void Build(int g,int l,int r){
T[g].l=l; T[g].r=r; T[g].mx=-(1<<30);
T[g].f.tot=0; T[g].f.mn=1<<30;
if(l==r) return ;
int mid=l+r>>1;
Build(g<<1,l,mid); Build(g<<1|1,mid+1,r);
T[g].f=T[g<<1].f*T[g<<1|1].f;
}
void Update(int g,int x,int y){
T[g].mx=max(T[g].mx,y);
if(T[g].l==T[g].r){
T[g].f.tot++; T[g].f.mn=y;
return ;
}
int mid=T[g].l+T[g].r>>1;
if(x<=mid) Update(g<<1,x,y);
else Update(g<<1|1,x,y);
T[g].f=T[g<<1].f*T[g<<1|1].f;
}
int Calc(int g,int l,int r){
if(T[g].l==l&&T[g].r==r) return T[g].f.tot;
int mid=T[g].l+T[g].r>>1;
if(r<=mid) return Calc(g<<1,l,r);
if(l>mid) return Calc(g<<1|1,l,r);
return Calc(g<<1,l,mid)+Calc(g<<1|1,mid+1,r);
}
int Find(int g,int l,int r){
if(T[g].l==l&&T[g].r==r) return T[g].mx;
int mid=T[g].l+T[g].r>>1;
if(r<=mid) return Find(g<<1,l,r);
if(l>mid) return Find(g<<1|1,l,r);
return max(Find(g<<1,l,mid),Find(g<<1|1,mid+1,r));
}
func Query(int g,int l,int r){
if(T[g].l==l&&T[g].r==r) return T[g].f;
int mid=T[g].l+T[g].r>>1;
if(r<=mid) return Query(g<<1,l,r);
if(l>mid) return Query(g<<1|1,l,r);
return Query(g<<1,l,mid)*Query(g<<1|1,mid+1,r);
}
inline bool check(int x){
int num=Calc(1,1,x),last=Find(1,1,x);
return last<=-num;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b[i]=parii(a[i],i);
sort(b+1,b+1+n);
for(int i=1;i<=n;i++) a[b[i].second]=i;
Build(1,1,n);
for(int i=1;i<=n;i++){
Update(1,a[i],b[a[i]].first);
int L=1,R=n,mid,cur=-1;
while(L<=R) check(mid=L+R>>1)?L=(cur=mid)+1:R=mid-1;
if(cur==-1) printf("%d\n",Query(1,1,n).val(0));
else{
int num=Calc(1,1,cur);
if(cur==n){ printf("%d\n",-num); continue; }
printf("%d\n",Query(1,cur+1,n).val(-num));
}
}
return 0;
}