比赛 膜你赛 评测结果 AAAAAAAAAAAAAAAAAAAA
题目名称 倚天剑的愤怒 最终得分 100
用户昵称 梦那边的美好ET 运行时间 14.923 s
代码语言 C++ 内存使用 331.22 MiB
提交时间 2019-04-29 14:12:14
显示代码纯文本
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#define LL long long
#define maxn 1000010
#define maxm 10000010
using namespace std;
LL a[maxn],f[maxn],x[maxn],ff[maxm],mind,kk,kkk,d,dd,minw;
LL lazy[maxn*4],mi1[maxn*4],wz1[maxn*4];
LL n,m,wz2[maxn*4],mi2[maxn*4],lin[maxm];
void pushdown(LL d){lazy[d*2]+=lazy[d];lazy[d*2+1]+=lazy[d];mi1[d*2]+=lazy[d];mi1[d*2+1]+=lazy[d];lazy[d]=0;}
void build(LL l,LL r,LL d){
	if(l==r){mi1[d]=f[l];mi2[d]=a[l];wz1[d]=wz2[d]=l;return;}
	LL m=(l+r)>>1;
	build(l,m,d*2);build(m+1,r,d*2+1);
	mi1[d*2]<=mi1[d*2+1]?wz1[d]=wz1[d*2]:wz1[d]=wz1[d*2+1];
	mi2[d*2]<=mi2[d*2+1]?wz2[d]=wz2[d*2]:wz2[d]=wz2[d*2+1];
	mi1[d]=min(mi1[d*2],mi1[d*2+1]);
	mi2[d]=min(mi2[d*2],mi2[d*2+1]);
	return;
}
void putit1(LL x,LL y,LL z,LL l,LL r,LL d){//区间加,维护区间min和min的位置],维护f[i] 
	if(x<=l&&y>=r){mi1[d]+=z;lazy[d]+=z;return;}
	if(lazy[d])pushdown(d);
	LL m=(l+r)>>1;
	if(x<=m)putit1(x,y,z,l,m,d*2);
	if(y>m)putit1(x,y,z,m+1,r,d*2+1);
	mi1[d*2]<=mi1[d*2+1]?wz1[d]=wz1[d*2]:wz1[d]=wz1[d*2+1];
	mi1[d]=min(mi1[d*2],mi1[d*2+1]);
	return;
}
void putit2(LL x,LL l,LL r,LL d){//单点清零。维护区间min,维护a[i] 
	if(l==r){mi2[d]=0;return;}
	LL m=(l+r)>>1;
	if(x<=m)putit2(x,l,m,d*2);
	else putit2(x,m+1,r,d*2+1);
	mi2[d*2]<=mi2[d*2+1]?wz2[d]=wz2[d*2]:wz2[d]=wz2[d*2+1];
	mi2[d]=min(mi2[d*2],mi2[d*2+1]);
	return;
}
LL findit(LL x,LL y,LL l,LL r,LL d){
	//mind-a[i](前缀min,即mi2[d])单调递增,f[i-1](前缀和的前缀min,即mi1[d])单调递减 
	//x=a[l-1],y=f[l-1] 
	if(l==r)return mind-min(a[l],x)>=y?l:-1;
	if(lazy[d])pushdown(d);
	LL m=(l+r)>>1;
	LL xx=min((LL)mi2[d*2],x),yy=min(y,mi1[d*2]);
	LL xxx=min(xx,a[m+1]);//xx=a[m+1],yy=f[m] 
	if(mind-xxx>=yy){//m+1合法?
		int kk=findit(x,y,l,m,d*2);
		return kk==-1?m+1:kk;
	}
	return findit(xx,yy,m+1,r,d*2+1);
}
LL find1(LL x,LL l,LL r,LL d){//求f[x] 
	if(x==0)return 1e18; 
	if(r<=x)return mi1[d];if (lazy[d])pushdown(d);
	LL m=(l+r)>>1;
	if(x<=m)return find1(x,l,m,d*2);
	return min(find1(x,m+1,r,d*2+1),mi1[d*2]);
}
LL find2(LL x,LL l,LL r,LL d){//求a[x] 
	if(r<=x)return mi2[d];
	LL m=(l+r)>>1;
	if(x<=m)return find2(x,l,m,d*2);
	return min(find2(x,m+1,r,d*2+1),(LL)mi2[d*2]);
}
LL find3(LL x,LL l,LL r,LL d){//求a[x]的位置 
	if(r<=x)return wz2[d];
	LL m=(l+r)>>1;
	if(x<=m)return find3(x,l,m,d*2);
	int k=find3(x,m+1,r,d*2+1);
	return a[k]>=mi2[d*2]?wz2[d*2]:k;
}
void check(LL x){
	if(x<1||x>n)return;
	LL xx=find1(x-1,1,n,1),yy=mind-find2(x,1,n,1);
	if(!kk)kk=x,kkk=min(xx,yy);
	else if(min(xx,yy)>kkk)kkk=min(xx,yy),kk=x;
	return;
}
bool pd(LL a,LL b){return x[a]>x[b];}
int main(){
	freopen("angryy.in","r",stdin);
	freopen("angryy.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(LL i=1;i<=n;i++)scanf("%lld",&a[i]),f[i]=f[i-1]+a[i];
	for(LL i=1;i<=m;i++)scanf("%lld",&x[i]),lin[i]=i;
	sort(lin+1,lin+1+m,pd);
	build(1,n,1);d=1;mind=-mi1[1];
	while(x[lin[d]]>=mind&&d<=m)d++;
	for(LL i=1;i<=n&&d<=m;i++){
		mind=mi1[1];minw=wz1[1];
		dd=findit(1e18,1e18,1,n,1);//找到第一个f[i-1]小于等于mind-a[i]的位置
		if(dd==-1)dd=n; 
		dd=min(dd,minw);kk=0;
		check(dd);check(dd-1);check(dd+1);
		kk=find3(kk,1,n,1);
		putit1(kk,n,-a[kk],1,n,1);
		putit2(kk,1,n,1);
		a[kk]=0;mind=-mi1[1];
		while(x[lin[d]]>=mind&&d<=m)ff[lin[d]]=i,d++;
		if(d>m)break;
	}
	for(LL i=1;i<=m;i++)printf("%lld\n",ff[i]);
	return 0;
}