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;
}
posted @ 2026-07-28 16:40  kzssCCC  阅读(8)  评论(0)    收藏  举报