传送门
题解:
首先容易注意到询问可以查分为前缀询问。
然后注意到询问本质上就是求 [ i − T , i ] [i-T,i] [i−T,i] 的最大值之和。
一个比较直接的思路是考虑每个值在答案中出现了多少次,发现不好维护,不过这可以给我们一些启发。
考虑统计每个位置上值的变化量。
构造一个平面直角坐标系,横坐标表示序列中的下标,纵坐标表示时间,每个整点上有一个值表示 S x ( y ) S_x(y) Sx(y)。
初始化所有位置的值为原序列中的值,考虑怎么通过若干次修改得到最终的平面。
对每个 i i i,求出它作为最大值存在的区间 ( l i , r i ) (l_i,r_i) (li,ri),容易发现我们需要考虑的就是 l i l_i li 什么时候覆盖 [ i , r i ) [i,r_i) [i,ri)。显然这是把平面上一个直角梯形区域 { ( x , y ) ∣ x ∈ [ i , r i ) , y ≥ x − l i } \{(x,y)|x\in[i,r_i),y\geq x-l_i\} {(x,y)∣x∈[i,ri),y≥x−li} 全部变为 a l i a_{l_i} ali,容易发现,如果我们从下到上进行覆盖操作,实际覆盖的区间中所有元素值是一样的,可以变为直角梯形上的加法。
直角梯形上的加法可以通过差分转化为直角三角形上的加法。
于是现在问题就是平面上一个形如 { ( x , y ) ∣ x ≥ a , y ≥ x − b } \{(x,y)|x\geq a,y\geq x-b\} {(x,y)∣x≥a,y≥x−b} 的区域的加法,同时在某个 y = t y=t y=t 的直线上询问 x ≤ p x\leq p x≤p的位置之和。
从下到上扫描线,考虑修改对询问的贡献,假设修改为 ( a , b , c ) (a,b,c) (a,b,c),其中 a , b a,b a,b 含义如上所示, c c c 表示权值。询问为 ( t , p ) (t,p) (t,p)。
容易发现贡献即为 c ⋅ ( min ( t + b , p ) − min ( p , a − 1 ) ) c\cdot(\min(t+b,p)-\min(p,a-1)) c⋅(min(t+b,p)−min(p,a−1))
t t t 在一加一减前缀差分中贡献没了,只剩下 c ⋅ ( min ( b , p − t ) − min ( p , a − 1 ) ) c\cdot(\min(b,p-t)-\min(p,a-1)) c⋅(min(b,p−t)−min(p,a−1))
树状数组维护即可。
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}template<typename T>T get_integer(){
char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x;
}inline int gi(){return get_integer<int>();}
}using namespace IO;
using std::cerr;
using std::cout;
cs int N=2e5+7;
int n,Q;
ll ans[N];
struct BIT{
ll a[N+N];BIT(){}
void add(int p,ll v){for(;p<=n+n;p+=p&-p)a[p]+=v;}
ll qy(int p)cs{ll r=0;for(;p>0;p&=p-1)r+=a[p];return r;}
};
struct structure{
BIT s,ss;structure(){}
void add(int p,int v){p+=n;s.add(1,v),s.add(p+1,-v),ss.add(p+1,(ll)p*v);}
ll qy(int p)cs{p+=n;return s.qy(p)*p+ss.qy(p);}
}t1,t2;
int a[N];ll sm[N];
int l[N],r[N];
int st[N],tp;
struct atom{int p,v;};
std::vector<atom> vec[N];
struct Qry{int l,r,id;};
std::vector<Qry> q[N];
void Main(){
n=gi(),Q=gi();
for(int re i=1;i<=n;++i)
a[i]=gi(),sm[i]=sm[i-1]+a[i];
for(int re i=1;i<=Q;++i){
int t=gi(),l=gi(),r=gi();
ans[i]=sm[r]-sm[l-1];
q[t].push_back({l-1,r,i});
}for(int re i=1;i<=n;++i){
while(tp&&a[i]>=a[st[tp]])
r[st[tp--]]=i;
l[i]=st[tp];st[++tp]=i;
}for(int re i=1;i<=n;++i)
if(l[i]){
vec[i-l[i]].push_back({i,a[l[i]]-a[i]});
if(r[i])vec[r[i]-l[i]].push_back({r[i],a[i]-a[l[i]]});
}
for(int re i=1;i<=n;++i){
for(auto &t:vec[i])
t1.add(t.p-i,t.v),t2.add(t.p-1,t.v);
for(auto &t:q[i])
ans[t.id]+=t1.qy(t.r-i)-t2.qy(t.r)
-t1.qy(t.l-i)+t2.qy(t.l);
}for(int re i=1;i<=Q;++i)cout<<ans[i]<<"\n";
}
inline void file(){
#ifdef zxyoi
freopen("fire.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}