「2017 山东二轮集训 Day3」第一题

题目描述

在这里插入图片描述
在这里插入图片描述

体节

贪心,每人每次分给的一定是所需代价最小的 v [ i ] − 1 v[i]-1 v[i]1个,且分给他的只需要比上一个人多一个。

代码

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const ll INF=1000000000019260817LL;
ll add(ll a,ll b)
{a+=b;return a>=INF?INF:a;}
const int Q=2000005;
ll sm[Q],v[Q],cmp[Q],lazy=0;
int tot=0;
int fa[Q],si[Q],ls[Q],rs[Q],ct[Q];
int rt=0;
void upd(int x)
{
	si[x]=si[ls[x]]+si[rs[x]]+ct[x];
	sm[x]=add(add(sm[ls[x]],sm[rs[x]]),v[x]);
}
void xxx(int x)
{
	int y=fa[x],z=fa[y];
	if(ls[z]==y)ls[z]=x;
	if(rs[z]==y)rs[z]=x;
	if(ls[y]==x)ls[y]=rs[x],rs[x]=y,fa[ls[y]]=y;
	else rs[y]=ls[x],ls[x]=y,fa[rs[y]]=y;
	fa[x]=z,fa[y]=x;
	upd(y),upd(x);
}
void splay(int x)
{
	while(fa[x])
	{
		int y=fa[x],z=fa[y];
		if(z)
			if((ls[z]==y&&ls[y]==x)||(rs[z]==y&&rs[y]==x))
				xxx(y),xxx(x);
			else xxx(x),xxx(x);
		else xxx(x);
	}
	rt=x;
}
void INS(ll val,int sz)
{
	ll ops=val*sz;
	if(!rt)
	{
		rt=++tot;
		v[tot]=sm[tot]=ops;
		si[tot]=ct[tot]=sz;
		cmp[tot]=val;
		return;
	}
	int p=rt;
	while(1)
	{
		si[p]+=sz;
		sm[p]=add(sm[p],ops);
		if(val==cmp[p])
		{
			v[p]=add(v[p],ops);
			ct[p]+=sz;
			splay(p);
			return;
		}
		if(val<cmp[p])
			if(ls[p])p=ls[p];
			else{ls[p]=++tot;break;}
		else if(rs[p])p=rs[p];
			else{rs[p]=++tot;break;}
	}
	fa[tot]=p;
	ct[tot]=si[tot]=sz;
	v[tot]=sm[tot]=ops;
	cmp[tot]=val;
	splay(tot);
}
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int R()
{
	int t=0;
	char o=GC;
	while(o>57||o<48)o=GC;
	while(o>=48&&o<=57){
		t=(t<<1)+(t<<3)+o-48;
		o=GC;
	}
	return t;
}
int main()
{
	int n,x;
	ll k;
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;i++)
	{
		++lazy;
		x=R();
		--x;
		if(x<=0)
		{
			printf("%lld\n",k);
			rt=0;
			INS(k-lazy,1);
			if(i>1)INS(-lazy,i-1);
			continue;
		}
		if(x>si[rt])
		{
			puts("-1");
			--lazy;
			INS(-1-lazy,1);
			continue;
		}
		int p=rt,now=x;
		while(1)
		{
			if(si[ls[p]]>=now)p=ls[p];
			else if(si[ls[p]]+ct[p]>=now)break;
			else now-=si[ls[p]]+ct[p],p=rs[p];
		}
		splay(p);
		ll mus=add(cmp[p]*((ll)x-si[ls[p]]),sm[ls[p]]);
		mus=add(mus,(ll)x*lazy);
		if(mus>k)
		{
			puts("-1");
			--lazy;
			INS(-1-lazy,1);
			continue;
		}
		printf("%lld\n",k-mus);
		int ned=i-1-x-si[rs[p]],wil=i-1-x;
		rs[p]=0;
		if(ned==ct[p])
		{
			if(!ls[p])rt=0;
			else{
				int m=ls[p];
				while(rs[m])m=rs[m];
				splay(m);
				rs[m]=0;
				upd(m);
			}
		}
		else ct[p]-=ned,v[p]-=cmp[p]*ned,upd(p);
		if(wil)INS(-lazy,wil);
		INS(k-mus-lazy,1);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值