题解:P12194 [NOISG 2025 Prelim] Snacks
题目传送门
思路
权值线段树+离散化乱搞。
先离线下来离散化一下。
权值线段树每个节点存一下值域内数的个数和它们总和,操作一就是区间修,操作二就是单点加。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+5;
struct problem {
ll l,r,x;
} t[N];
ll n,q,a[N];
ll z[4*N],p[4*N],cnt,tot;
map<ll,ll> mp1,mp2;
struct node {
int l,r;
ll zs,sm;
bool laz;
} tr[16*N];
void up(int pos) {
tr[pos].sm=tr[pos*2].sm+tr[pos*2+1].sm;
tr[pos].zs=tr[pos*2].zs+tr[pos*2+1].zs;
}
void pd(int pos) {
if(!tr[pos].laz) return;
tr[pos*2].laz=tr[pos*2+1].laz=1;
tr[pos*2].sm=tr[pos*2].zs=0;
tr[pos*2+1].sm=tr[pos*2+1].zs=0;
tr[pos].laz=0;
}
void bd(int l,int r,int pos) {
tr[pos].l=l,tr[pos].r=r;
if(l==r) {
tr[pos].zs=mp2[l];
tr[pos].sm=tr[pos].zs*p[l];
return;
}
int mid=(l+r)/2;
bd(l,mid,pos*2);bd(mid+1,r,pos*2+1);
up(pos);
}
ll qs(int l,int r,int pos) {
if(tr[pos].l>r||tr[pos].r<l) return 0;
if(tr[pos].l>=l&&tr[pos].r<=r) {
tr[pos].laz=1;
ll res=tr[pos].zs;
tr[pos].sm=tr[pos].zs=0;
return res;
}
pd(pos);
ll res=qs(l,r,pos*2)+qs(l,r,pos*2+1);
up(pos);
return res;
}
void pl(int gl,int pos,int val) {
if(tr[pos].l>gl||tr[pos].r<gl) return;
if(tr[pos].l==tr[pos].r) {
tr[pos].zs+=val;
tr[pos].sm+=val*p[tr[pos].l];
return;
}
pd(pos);
pl(gl,pos*2,val);pl(gl,pos*2+1,val);
up(pos);
}
void init() {
sort(z+1,z+tot+1);
z[0]=-1;
for(int i=1;i<=tot;i++) {
if(z[i]!=z[i-1]) {
p[++cnt]=z[i];
mp1[z[i]]=cnt;
}
}
for(int i=1;i<=n;i++) mp2[mp1[a[i]]]++;
}
void aswr() {printf("%lld\n",tr[1].sm);}
int main() {
cin>>n>>q;
for(int i=1;i<=n;i++) {
scanf("%lld",&a[i]);
z[++tot]=a[i];
}
for(int i=1;i<=q;i++) {
scanf("%lld %lld %lld",&t[i].l,&t[i].r,&t[i].x);
z[++tot]=t[i].l,z[++tot]=t[i].r,z[++tot]=t[i].x;
}
init();
bd(1,cnt,1);aswr();
for(int i=1;i<=q;i++) {
ll l=mp1[t[i].l],r=mp1[t[i].r],x=mp1[t[i].x];
ll gd=qs(l,r,1);
pl(x,1,gd);
aswr();
}
}