其他分享
首页 > 其他分享> > [冲刺国赛2022] 草莓蛋糕

[冲刺国赛2022] 草莓蛋糕

作者:互联网

一、题目

两个多重集 \(A,B\),其中每个元素都有两个属性 \(a,b\),取 \(x\in A,y\in B\),最小化:

\[\max(a_x+a_y,b_x+b_y) \]

有 \(m\) 次修改,每次修改会对 \(A/B\) 进行一次插入\(/\)删除,你需要动态地维护这个最小值。

\(m\leq 10^6\)

二、解法

考试的时候只会线段树分治,脑子还是不行啊...

考虑用分类讨论的方法来处理 \(\max\),如果 \(a_x+a_y\geq b_x+b_y\),即 \(a_x-b_x\geq b_y-a_y\),那么最后的取值是 \(a_x+a_y\),设 \(h_x=a_x-b_x,h_y=b_y-a_y\),那么条件就是 \(h_x\geq h_y\);同理如果取值是 \(b_x+b_y\),条件是 \(h_x\leq h_y\)

那么以 \(h\) 建立一棵线段树,线段树的底层用 \(\tt multiset\) 维护插入和删除,合并的时候由于天然带有 \(h\) 的偏序关于,所以只需要维护四类值的最小值,就可以支持合并,时间复杂度 \(O(n\log n)\)

三、总结

本题中的 \(\max\) 相当于把 \(x,y\) 混合到了一起,不好处理;若是使用拆分法,拆分成独立的性质就是便于维护的。

#pragma GCC optimize("Ofast")
#pragma GCC target("avx", "sse")
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int M = 1000005;
#define int long long
const int inf = 2e9+7;
int read()
{
	int 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;
}
int n,m,h[M],o[M],op[M],d[M],a[M],b[M];
int mi[M<<2][4],tr[M<<2];multiset<int> s[M][4];
void build(int i,int l,int r)
{
	tr[i]=2147483647;
	for(int j=0;j<4;j++) mi[i][j]=inf;
	if(l==r)
	{
		for(int j=0;j<4;j++) s[l][j].insert(inf);
		return ;
	}
	int mid=(l+r)>>1;
	build(i<<1,l,mid);
	build(i<<1|1,mid+1,r);
}
void ins(int i,int l,int r,int id,int x)
{
	if(l==r)
	{
		int p=d[x]==0?0:2;
		if(op[x]==1)
		{
			s[l][p].insert(a[x]);
			s[l][p+1].insert(b[x]);
		}
		else
		{
			s[l][p].erase(s[l][p].find(a[x]));
			s[l][p+1].erase(s[l][p+1].find(b[x]));
		}
		tr[i]=min(*s[l][0].begin()+*s[l][2].begin(),
		*s[l][1].begin()+*s[l][3].begin());
		for(int j=0;j<4;j++) mi[i][j]=*s[l][j].begin();
		return ;
	}
	int mid=(l+r)>>1;
	if(mid>=id) ins(i<<1,l,mid,id,x);
	else ins(i<<1|1,mid+1,r,id,x);
	for(int j=0;j<4;j++)
		mi[i][j]=min(mi[i<<1][j],mi[i<<1|1][j]);
	tr[i]=min(min(tr[i<<1],tr[i<<1|1]),
	min(mi[i<<1][2]+mi[i<<1|1][0],
	mi[i<<1][1]+mi[i<<1|1][3]));
}
signed main()
{
	freopen("cake.in","r",stdin);
	freopen("cake.out","w",stdout);
	m=read();
	for(int i=1;i<=m;i++)
	{
		op[i]=read();d[i]=read();
		a[i]=read();b[i]=read();
		o[i]=h[i]=!d[i]?a[i]-b[i]:b[i]-a[i];
	}
	sort(o+1,o+1+m);
	n=unique(o+1,o+1+m)-o-1;
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		h[i]=lower_bound(o+1,o+1+n,h[i])-o;
		ins(1,1,n,h[i],i);
		printf("%lld\n",tr[1]>=inf?-1:tr[1]);
	}
}

标签:geq,int,max,草莓,国赛,2022,维护,include,线段
来源: https://www.cnblogs.com/C202044zxy/p/16491771.html