傳送門
題解:
首先容易注意到詢問可以查分爲前綴詢問。
然後注意到詢問本質上就是求 的最大值之和。
一個比較直接的思路是考慮每個值在答案中出現了多少次,發現不好維護,不過這可以給我們一些啓發。
考慮統計每個位置上值的變化量。
構造一個平面直角座標系,橫座標表示序列中的下標,縱座標表示時間,每個整點上有一個值表示 。
初始化所有位置的值爲原序列中的值,考慮怎麼通過若干次修改得到最終的平面。
對每個 ,求出它作爲最大值存在的區間 ,容易發現我們需要考慮的就是 什麼時候覆蓋 。顯然這是把平面上一個直角梯形區域 全部變爲 ,容易發現,如果我們從下到上進行覆蓋操作,實際覆蓋的區間中所有元素值是一樣的,可以變爲直角梯形上的加法。
直角梯形上的加法可以通過差分轉化爲直角三角形上的加法。
於是現在問題就是平面上一個形如 的區域的加法,同時在某個 的直線上詢問 的位置之和。
從下到上掃描線,考慮修改對詢問的貢獻,假設修改爲 ,其中 含義如上所示, 表示權值。詢問爲 。
容易發現貢獻即爲
在一加一減前綴差分中貢獻沒了,只剩下
樹狀數組維護即可。
#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;}