ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[提高组集训2021] 大套子

2021-10-05 20:03:53  阅读:161  来源: 互联网

标签:ll int sum bk num 2021 套子 集训


一、题目

校长有一个体积为 \(x\) 的大套子,现在有 \(n\) 条人类,如果套子的体积严格大于人类的体积 \(y\),那么校长就会把这个人类装在套子里,套子的体积就会增加 \(y\)

有下列三种可能的时间:

  • 校长得到了一个大小为 \(x\) 的套子,他想让套子的大小至少变成 \(y\),如果可以输出步数,否则输出 \(-1\)
  • 新来了一条体积为 \(y\) 的人类
  • 离开了一条体积为 \(y\) 的人类

\(n\leq 3\cdot 10^5,q\leq 10^5\)

二、解法

贪心的做法是每次套能套的最大人类,但暴力进行此过程显然会 \(\tt T\)

这个东西也不是很好维护,所以要想一些在线的做法,我们想要让套的次数是 \(\tt log\) 级的,所以我们一次套多点呗。具体来说我们套到能套一个更大的人类为止,那么这样做两次可以让套子大小翻倍。

对于所有小于 \(x\) 的人类,我们把它们都放在权值线段树上,每次在线段树上二分一段后缀即可,时间复杂度 \(O(n\log^2n)\)

难点是实现细节,二分的时候如果我们要套人类,直接把这个节点的信息清零,以后不访问信息被清零的节点即可(不需要打标记),但是因为询问独立所以我们要回退,拿个栈记录一下我们所有在线段树上的修改即可。

三、总结

对于这类在线处理的增量型问题,考虑怎样才能只做 \(\log n\) 次。

#pragma GCC optimize(2)
#include <cstdio>
#include <stack>
#include <map>
using namespace std;
#define ll long long
#define int long long
const int N = 13000005;
const ll up = 1e12;
ll read()
{
	ll x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
ll n,m,sum[N],num[N];int rt,ls[N],rs[N],fa[N];
ll cnt,ans,x,y,rm;map<ll,ll> mp;
struct node{ll x,y,z;};stack<node> bk;
void upload(int x)
{
	sum[x]=sum[ls[x]]+sum[rs[x]];
	num[x]=num[ls[x]]+num[rs[x]];
	fa[ls[x]]=fa[rs[x]]=x;
}
void ins(int &x,ll l,ll r,ll id,ll f)
{
	if(!x) x=++cnt;
	num[x]+=f;
	sum[x]+=f*id;
	if(l==r) return ;
	ll mid=(l+r)>>1;
	if(mid>=id) ins(ls[x],l,mid,id,f);
	else ins(rs[x],mid+1,r,id,f);
}
void add(int &i,ll l,ll r)
{
	if(l>=x || !sum[i] || !i || rm<=0) return ;
	if(l==r)
	{
		ll tmp=min((rm+l-1)/l,num[i]);
		rm-=tmp*l;x+=tmp*l;ans+=tmp;
		bk.push(node{i,sum[i],num[i]});
		sum[i]-=tmp*l;num[i]-=tmp;
		return ;
	}
	ll mid=(l+r)>>1;
	if(r<=x && sum[i]<=rm)
	{
		rm-=sum[i];x+=sum[i];ans+=num[i];
		bk.push(node{i,sum[i],num[i]});
		sum[i]=num[i]=0;
		return ;
	}
	add(rs[i],mid+1,r);
	add(ls[i],l,mid);
	upload(i);
}
void work()
{
	ans=0;
	while(x<y)
	{
		map<ll,ll>::iterator it=mp.lower_bound(x);
		ll to=y-1;
		if(it!=mp.end()) to=min(to,it->first);
		rm=to-x+1;
		add(rt,1,up);
		if(rm>0) break;
	}
	while(!bk.empty())
	{
		ll t=bk.top().x;
		sum[t]=bk.top().y;
		num[t]=bk.top().z;
		while(t!=rt)
		{
			t=fa[t];
			upload(t);
		}
		bk.pop();
	}
	if(x<y) puts("-1");
	else printf("%lld\n",ans);
}
signed main()
{
	freopen("fish.in","r",stdin);
	freopen("fish.out","w",stdout);
	n=read();
	for(ll i=1;i<=n;i++)
	{
		ll x=read();mp[x]++;
		ins(rt,1,up,x,1);
	}
	m=read();
	while(m--)
	{
		ll op=read();x=read();
		if(op==2)
		{
			mp[x]++;
			ins(rt,1,up,x,1);
		}
		if(op==3)
		{
			mp[x]--;
			if(!mp[x]) mp.erase(x);
			ins(rt,1,up,x,-1);
		}
		if(op==1)
		{
			y=read();work();
		}
	}
}

标签:ll,int,sum,bk,num,2021,套子,集训
来源: https://www.cnblogs.com/C202044zxy/p/15369362.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有