atc abc167F 思路分享(线段树)
https://atcoder.jp/contests/abc467/tasks/abc467_f
题意
给定长为 \(n\) 的序列 \(A,B\),给第 \(i\) 个公司写邮件花费 \(A_i\) 时间,该公司回信花费 \(B_i\) 时间,不能同时写两份邮件,求接受到所有公司回信的最短时间.
有 \(q\) 个询问,每个询问三个参数 op i x,若 \(op=1\),\(A_i:=x\);若 \(op=2\),\(B_i:=x\),每个询问输出最短时间.
\(1\le n,q \le 10^5\).
思路
交换论证可知,按 \(B_i\) 降序写信最优,因此排序后:
\[ans = \max_{i}{(\sum_{j=1}^{i}{A_j}+B_i)}
\]
转化成值域,令 \(S_b = \sum_{B_i=b}{A_i}\),则:
\[ans = \max_{b}{(\sum_{p\ge b}{S_p}+b)}
\]
考虑用线段树维护,先离散化,并实时维护最大的 \(b\).
每个修改操作:
-
\(op=1\),对 \([1,B_i]\) 区间加 \(x-A_i\).
-
\(op=2\),对 \([1,B_i]\) 区间减 \(A_i\),对 \([1,x]\) 区间加 \(A_i\).
时间复杂度 \(\mathcal{O}((n+q)\log (n+q))\).
代码
//author:kzssCCC
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = 9e18;
class segmentTree{
public:
class node{
public:
ll mx = -INF;
ll lazy = 0;
};
int n;
vector<node> seg;
segmentTree(int _n){
n = _n;
seg = vector<node>(4*n+1);
}
node merge(node p1,node p2){
node temp;
temp.mx = max(p1.mx,p2.mx);
return temp;
}
void build(vector<ll>& a){
build(1,1,n,a);
}
void build(int rt,int l,int r,vector<ll>& a){
if (l==r){
seg[rt].mx = a[l];
return;
}
int mid = l+r >> 1;
build(rt<<1,l,mid,a);
build(rt<<1|1,mid+1,r,a);
seg[rt] = merge(seg[rt<<1],seg[rt<<1|1]);
}
void push_down(int rt,int l,int r){
if (seg[rt].lazy==0) return;
seg[rt<<1].mx += seg[rt].lazy;
seg[rt<<1].lazy += seg[rt].lazy;
seg[rt<<1|1].mx += seg[rt].lazy;
seg[rt<<1|1].lazy += seg[rt].lazy;
seg[rt].lazy = 0;
}
void update(int pos,ll val){
if (pos<1 || pos>n) return;
update(1,1,n,pos,val);
}
void update(int rt,int l,int r,int pos,ll val){
if (l==r){
//
return;
}
int mid = l+r >> 1;
push_down(rt,l,r);
if (pos<=mid){
update(rt<<1,l,mid,pos,val);
}
else{
update(rt<<1|1,mid+1,r,pos,val);
}
seg[rt] = merge(seg[rt<<1],seg[rt<<1|1]);
}
void update_range(int x,int y,ll val){
if (x>y || x<1 || x>n || y<1 || y>n) return;
update_range(1,1,n,x,y,val);
}
void update_range(int rt,int l,int r,int x,int y,ll val){
if (r<x || l>y){
return;
}
if (x<=l && y>=r){
seg[rt].mx += val;
seg[rt].lazy += val;
return;
}
int mid = l+r >> 1;
push_down(rt,l,r);
update_range(rt<<1,l,mid,x,y,val);
update_range(rt<<1|1,mid+1,r,x,y,val);
seg[rt] = merge(seg[rt<<1],seg[rt<<1|1]);
}
node query(int pos){
if (pos<1 || pos>n) return {};
return query(1,1,n,pos);
}
node query(int rt,int l,int r,int pos){
if (l==r){
return seg[rt];
}
int mid = l+r >> 1;
push_down(rt,l,r);
if (pos<=mid){
return query(rt<<1,l,mid,pos);
}
else{
return query(rt<<1|1,mid+1,r,pos);
}
}
node query_range(int l,int r){
if (l<1 || l>n || r<1 || r>n || l>r) return {};
return query_range(1,1,n,l,r);
}
node query_range(int rt,int l,int r,int x,int y){
if (r<x || l>y){
return {};
}
if (x<=l && y>=r){
return seg[rt];
}
int mid = l+r >> 1;
push_down(rt,l,r);
return merge(query_range(rt<<1,l,mid,x,y),query_range(rt<<1|1,mid+1,r,x,y));
}
bool is_valid(int rt,int l,int r,int x,int y,ll val){
if (r<x || l>y) return false;
//
return false;
}
int first_valid(int l,int r,ll val){
if (l>r || l<1 || l>n || r<1 || r>n) return -1;
return first_valid(1,1,n,l,r,val);
}
int first_valid(int rt,int l,int r,int x,int y,ll val){
if (!is_valid(rt,l,r,x,y,val)) return -1;
if (l==r){
return l;
}
int mid = l+r >> 1;
push_down(rt,l,r);
int res = first_valid(rt<<1,l,mid,x,y,val);
if (res!=-1){
return res;
}
return first_valid(rt<<1|1,mid+1,r,x,y,val);
}
int last_valid(int l,int r,ll val){
if (l>r || l<1 || l>n || r<1 || r>n) return -1;
return last_valid(1,1,n,l,r,val);
}
int last_valid(int rt,int l,int r,int x,int y,ll val){
if (!is_valid(rt,l,r,x,y,val)) return -1;
if (l==r){
return l;
}
int mid = l+r >> 1;
push_down(rt,l,r);
int res = last_valid(rt<<1|1,mid+1,r,x,y,val);
if (res!=-1){
return res;
}
return last_valid(rt<<1,l,mid,x,y,val);
}
};
void solve(){
int n,q;
cin >> n >> q;
vector<int> a(n+1),b(n+1),uni{0};
for (int i=1;i<=n;i++){
cin >> a[i];
}
for (int i=1;i<=n;i++){
cin >> b[i];
uni.push_back(b[i]);
}
vector<array<int,3>> que(q+1);
for (int t=1;t<=q;t++){
int op,i,x;
cin >> op >> i >> x;
que[t] = {op,i,x};
if (op==2) uni.push_back(x);
}
sort(uni.begin()+1,uni.end());
uni.erase(unique(uni.begin()+1,uni.end()),uni.end());
int m = uni.size()-1;
vector<int> ref(m+1);
for (int i=1;i<=n;i++){
int pos = lower_bound(uni.begin()+1,uni.end(),b[i])-uni.begin();
ref[pos] = b[i];
b[i] = pos;
}
for (int t=1;t<=q;t++){
auto& [op,i,x] = que[t];
if (op==2){
int pos = lower_bound(uni.begin()+1,uni.end(),x)-uni.begin();
ref[pos] = x;
x = pos;
}
}
vector<ll> suf(m+2);
for (int i=1;i<=n;i++){
suf[b[i]] += a[i];
}
for (int i=m;i>=1;i--){
suf[i] += suf[i+1];
}
multiset<int> st;
for (int i=1;i<=n;i++){
st.insert(b[i]);
}
for (int i=1;i<=m;i++){
suf[i] += ref[i];
}
segmentTree sg(m);
sg.build(suf);
for (int t=1;t<=q;t++){
auto& [op,i,x] = que[t];
if (op==1){
sg.update_range(1,b[i],x-a[i]);
a[i] = x;
}
else{
sg.update_range(1,b[i],-a[i]);
sg.update_range(1,x,a[i]);
st.extract(b[i]);
st.insert(x);
b[i] = x;
}
cout << sg.query_range(1,*st.rbegin()).mx << '\n';
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t = 1;
// cin >> t;
while (t--) solve();
return 0;
}

浙公网安备 33010602011771号