[NERC2023] Great City Saint Petersburg 题解
跟 [ROIR 2025 Day 1] 酸雨 是同一个 trick。俄国人都这么喜欢出接雨水题吗。
考虑位置
以前缀为例,讨论区间
放代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
class segtree_max{
private:
int k,m;
vector<int> S,T;
inline void pushup(int u){
S[u]=max(S[u<<1],S[u<<1|1]);
}
inline void apply(int u,int d){
S[u]+=d,T[u]+=d;
}
inline void pushdown(int u){
if(T[u]){
S[u<<1]+=T[u],S[u<<1|1]+=T[u];
T[u<<1]+=T[u],T[u<<1|1]+=T[u],T[u]=0;
}
}
public:
segtree_max(vector<int> a){
int n=a.size();
k=__lg(n)+(__builtin_popcount(n)>1);
S.resize((m=1<<k)<<1),T.resize(m<<1);
for(int i=0;i<n;i++)
S[i+m]=a[i];
for(int i=m-1;i;i--)
pushup(i);
}
inline void update(int l,int r,int d=1){
l+=m,r+=m+1;
for(int i=k;i;i--){
if((l>>i<<i)!=l)pushdown(l>>i);
if((r>>i<<i)!=r)pushdown(r-1>>i);
}
int l2=l,r2=r;
while(l2<r2){
if(l2&1)apply(l2++,d);
if(r2&1)apply(--r2,d);
l2>>=1,r2>>=1;
}
for(int i=1;i<=k;i++){
if((l>>i<<i)!=l)pushup(l>>i);
if((r>>i<<i)!=r)pushup(r-1>>i);
}
}
inline int prod(int l,int r){
l+=m,r+=m+1;
for(int i=k;i;i--){
if((l>>i<<i)!=l)pushdown(l>>i);
if((r>>i<<i)!=r)pushdown(r-1>>i);
}
int c=0;
while(l<r){
if(l&1)c=max(c,S[l++]);
if(r&1)c=max(c,S[--r]);
l>>=1,r>>=1;
}
return c;
}
}; // 维护区间加、区间 max 的线段树
class segtree_sum{
private:
int k,m;
vector<pair<ll,int> > S;
vector<ll> T;
inline void pushup(int u){
S[u].first=S[u<<1].first+S[u<<1|1].first;
S[u].second=S[u<<1].second+S[u<<1|1].second;
}
inline void apply(int u,int d){
S[u].first+=(ll)d*S[u].second,T[u]+=d;
}
inline void pushdown(int u){
if(T[u]){
S[u<<1].first+=T[u]*S[u<<1].second;
S[u<<1|1].first+=T[u]*S[u<<1|1].second;
T[u<<1]+=T[u],T[u<<1|1]+=T[u],T[u]=0;
}
}
public:
segtree_sum(vector<int> a){
int n=a.size();
k=__lg(n)+(__builtin_popcount(n)>1);
S.resize((m=1<<k)<<1),T.resize(m<<1);
for(int i=0;i<n;i++)
S[i+m]=make_pair(a[i],1);
for(int i=m-1;i;i--)
pushup(i);
}
inline int get(int p){
p+=m;
for(int i=k;i;i--)
pushdown(p>>i);
return S[p].first;
}
inline void update(int l,int r,int d=1){
l+=m,r+=m+1;
for(int i=k;i;i--){
if((l>>i<<i)!=l)pushdown(l>>i);
if((r>>i<<i)!=r)pushdown(r-1>>i);
}
int l2=l,r2=r;
while(l2<r2){
if(l2&1)apply(l2++,d);
if(r2&1)apply(--r2,d);
l2>>=1,r2>>=1;
}
for(int i=1;i<=k;i++){
if((l>>i<<i)!=l)pushup(l>>i);
if((r>>i<<i)!=r)pushup(r-1>>i);
}
}
inline ll all_prod(){return S[1].first;}
}; // 维护区间加、区间和的线段树
main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n,q,mx=0; ll s=0; cin>>n>>q;
vector<int> a(n);
for(auto &i:a)cin>>i,s+=i,mx=max(mx,i);
vector<int> pr(n),sf(n);
for(int i=0;i<n;i++)
pr[i]=max(i?pr[i-1]:0,a[i]);
for(int i=n-1;~i;i--)
sf[i]=max(i<n-1?sf[i+1]:0,a[i]);
segtree_max t(a);
segtree_sum tp(pr),ts(sf);
cout<<tp.all_prod()+ts.all_prod()-(ll)mx*n-s<<'\n';
while(q--){
int l,r; cin>>l>>r,l--,r--;
int m=t.prod(l,r);
mx=max(mx,m+1),s+=r-l+1;
{
int L=-1,R=-1;
int x=l,y=r+1;
while(x<y){
int md=x+y>>1;
if(md==r+1||tp.get(md)==t.prod(l,md))y=md;
else x=md+1;
}
if(y<=r){
L=y,x=r,y=n-1;
while(x<y){
int md=x+y+1>>1;
if(tp.get(md)==m)x=md;
else y=md-1;
}
R=x,tp.update(L,R);
}
} // 更新前缀
{
int L=-1,R=-1;
int x=l-1,y=r;
while(x<y){
int md=x+y+1>>1;
if(md==l-1||ts.get(md)==t.prod(md,r))x=md;
else y=md-1;
}
if(y>=l){
R=x,x=0,y=l;
while(x<y){
int md=x+y>>1;
if(ts.get(md)==m)y=md;
else x=md+1;
}
L=y,ts.update(L,R);
}
} // 更新后缀
t.update(l,r);
cout<<tp.all_prod()+ts.all_prod()-(ll)mx*n-s<<'\n';
}
return 0;
}