题解:AT_abc467_f [ABC467F] Email Scheduling Optimization

题意

给定一个长度为 $n$ 二元组序列 ${(a_n,b_n)}$,有 $q$ 次修改,每次修改 $a_i$ 或 $b_i$ 的值。设存在一个长度为 $n$ 的排列 ${p_n}$,对于 $s_i = \sum_{j=1}^i{a_{p_i}}$ 要求每次修改后求出对于所有可能的 $p_n$ 中 $\max_{i=1}^n{s_i+b_{p_i}}$ 最小。
$1\le a,b \le 10^9$

思路

这题很如果不看修改操作是很经典的一道贪心题目,对于每个二元组序列,只需要把其按 $b_i$ 从大到小排序后对于每一项分别求值,取最大值就是所求。

具体证明可以用邻项交换法。

设排序后相邻两项排序后满足 $i = j-1$,$b_i \ge b_j$。
此时两项的贡献分别为 $a_i+b_i$ 与 $a_i+a_j+b_j$。
若交换两项,则贡献变为 $a_j+b_j$ 与 $a_i+a_j+b_i$。
则只需要证明 $\max(a_i+b_i,a_i+a_j+b_j) \le \max(a_j+b_j,a_i+a_j+b_i)$ 即可。

因为 $b_i \ge b_j$,所以 $\max(a_j+b_j,a_i+a_j+b_i) = a_i+a_j+b_i$,而 $a_i+a_j+b_i$ 同时不小于左侧两项,所以得证交换后不会更优。

所以对于每一项,因为要重排,所以 $i$ 的顺序不重要,我们只关心 $a_i$ 与 $b_i$ 的大小。设每一项 $i$ 贡献为 $f_i$,则 $,f_i = (\sum_{b_j\le b_i} a_j)+b_i$,当然贡献包括自己。

可以离散化所有初始与离散化的 $b_i$,用线段树以 $b_i$ 为下标维护贡献,则只需要维护全局最大值和区间加,对于修改,可以先把贡献减去再重新加上新的贡献。

细节方面,对于 $b_i$ 相同的部分是等价的,所以相对位置不重要,但不可以用同一个下标因为 $b_i$ 不能累加,可以离散化时候分别给予不同下标,还有记得开longlong。数组空间要开够。

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+15;
#define ll long long
int n,q,cnt;
ll a[N],b[N],d[N<<1],num[N];
ll tag[N<<4],mx[N<<4];
int t[N<<2];

int opt[N],id[N];


#define ls (p<<1)
#define rs (p<<1|1)
#define mid (l+r>>1)
void pushdown(int p){
	mx[ls]+=tag[p];
	mx[rs]+=tag[p];
	tag[ls]+=tag[p];
	tag[rs]+=tag[p];
	tag[p]=0;
}
void update(int sl,int sr,ll k,int p = 1,int l = 1,int r = cnt){
	if(sl<=l&&sr>=r){
		mx[p] += k;
		tag[p] += k;
		return;
	}
	pushdown(p);
	if(sl<=mid)update(sl,sr,k,ls,l,mid);
	if(sr>mid)update(sl,sr,k,rs,mid+1,r);
	mx[p] = max(mx[ls],mx[rs]);
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie();
	cin >> n >> q;
	for(int i = 1;i <= n;++i)cin >> a[i];
	for(int i = 1;i <= n;++i){
		cin >> b[i];
		d[++cnt]=b[i];
	}
	for(int i = 1;i <= q;++i){
		cin >> opt[i] >> id[i] >> num[i];
		if(opt[i]==2)d[++cnt] = num[i];
	}
	sort(d+1,d+cnt+1);
	for(int i = 1;i <= n;++i){
		b[i] = lower_bound(d+1,d+cnt+1,b[i])-d;
		t[b[i]]++;
		b[i]+=t[b[i]]-1;
	}
	for(int i = 1;i <= q;++i){
		if(opt[i]==2){
			num[i] = lower_bound(d+1,d+cnt+1,num[i])-d;
			t[num[i]]++;
			num[i]+=t[num[i]]-1;
		}
	}
	for(int i = 1;i <= n;++i){
		update(1,b[i],a[i]);
		update(b[i],b[i],d[b[i]]);
	}
	int i;
	for(int j = 1;j <= q;++j){
		i = id[j];
		if(opt[j]==1){
			update(1,b[i],num[j]-a[i]);
			a[i] = num[j];
			printf("%lld\n",mx[1]);
		}
		else {
			update(1,b[i],-a[i]);
			update(b[i],b[i],-d[b[i]]);
			b[i] = num[j];
			update(1,b[i],a[i]);
			update(b[i],b[i],d[b[i]]);
			printf("%lld\n",mx[1]);
		}
	}
	return 0;
}
posted @ 2026-07-23 16:04  依绫  阅读(3)  评论(0)    收藏  举报