题解: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;
}

浙公网安备 33010602011771号