P12194 [NOISG 2025 Prelim] Snacks 题解

废话时间

我。永远。喜欢。珂朵莉。

一开始看错了,以为是 $l_i$ 和 $r_i$ 是指下标,自顾自地说怎么这么简单。打完之后直接测试样例,发现错了,再返回看题面,发现维护的是值域,然后尖锐爆鸣。

正文

值域珂朵莉树,比较好想。

我们可以直接考虑珂朵莉树的每个节点表示的是什么意思。设 ${l,r,v}$ 表示对于 $i\in[l,r]$,$(\sum_{j=1}^n[i=a_j])=v$。那么题目中的操作就能直接转化为给区间内的数全都置为 $0$,然后再给节点 $v$ 加上区间内的数对应原数组中对应多少个数就行了。那么这就能直接抽象为一个区间推平和单点修改,可以直接使用珂朵莉树维护。

其实将操作看作区间推平和单点修改后,有很多种维护方法,比如线段树或者树状数组。但是有了区间推平的操作,感觉还是珂朵莉树好些一些。

代码

#include<bits/stdc++.h>
using std::set;
using std::cin;
using std::cout;
using std::ios;

#define int long long

struct node{
    int l,r;
    mutable int v;

    node(int a=0,int b=-1,int c=0):l(a),r(b),v(c){}

    bool operator<(const node &o)const{
        return l<o.l;
    }
};

set<node> s;

int ans,l,r,n,q,x;

auto split(int pos){
    auto it=s.lower_bound(node(pos));
    if(it!=s.end()&&it->l==pos) return it;
    --it;
    int l=it->l,r=it->r,v=it->v;
    s.erase(it);
    s.insert(node(l,pos-1,v));
    return s.insert(node(pos,r,v)).first;
}

void upd(int d,int k){
    auto ir=split(d+1),il=split(d);
    for(auto it=il;it!=ir;++it)
        it->v+=k;
    ans+=d*k;
}

int asg(int l,int r,int k){
    int sum=0;
    auto ir=split(r+1),il=split(l);
    for(auto it=il;it!=ir;++it){
        ans-=(it->r+it->l)*(it->r-it->l+1)/2*it->v;
        sum+=(it->r-it->l+1)*it->v;
    }
    s.erase(il,ir);
    s.insert(node(l,r,0));
    upd(k,sum);
    return ans;
}

void solve(){
    cin>>n>>q;
    s.insert(node(0,1e9,0));
    for(int i=1;i<=n;i++)
        cin>>x,upd(x,1);
    cout<<ans<<"\n";
    while(q--){
        cin>>l>>r>>x;
        cout<<asg(l,r,x)<<"\n";
    }
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    solve();
    return 0;
}

感谢阅读。

posted @ 2026-09-22 21:03  Colubrid_L  阅读(3)  评论(0)    收藏  举报