一、题目
两个多重集 \(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]);
}
}