瓜野高彦
takanashi_mifuru · · 题解
我从来没有想过这个专栏名字真的能和题目名字这么契合。。
开题不会做,数据范围根号能过,先想想分块。
首先这个东西转化一下就是时刻
考虑分块之后变成了整块和散块,散块可以 ST 表直接查询,问题就是整块。
考虑如果我们能对第
如果要维护每个点的变化这是不可能求出的,我们考虑只考虑这个块,如果块外面有一个神秘权值想要影响进来的话,他必须打过第一个点,这意味着每次从外面进来的权值必然是递增的,这启发我们暴力计算块内贡献再考虑块外贡献。
具体地,先用 ST 表暴力算出
这个东西是很好实现的,所以就做完了。
当然 256 兆肯定存不下,逐块处理就可以了。
时间复杂度
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<ctime>
#define ll long long
#define rep(i, f, t) for (int i = (f), ed##i = (t); i <= ed##i; ++i)
#define re(i, t) rep (i, 1, t)
#define per(i, t, f) for (int i = (t), ed##i = (f); i >= ed##i; --i)
#define ste(i, f, t, s) for (int i = (f), ed##i = (t); i <= ed##i; i += s)
#define each(i, x) for (auto& i : (x))
#define nxt(i, f, g) for (int i = g.h[f]; i; i = g.e[i].n)
#define dbg(x) (cerr << "(dbg) " << #x " = " << (x) << '\n')
#define umod(x) ((x) >= mo && ((x) -= mo))
#define dmod(x) ((x) < 0 && ((x) += mo))
#define up(x, y) (((x) < (y)) && ((x) = (y)))
#define down(x, y) (((x) > (y)) && ((x) = (y)))
#define y1 y1__
namespace FastIO {
const int SZ=(1<<23)+1;
struct I {
char ibuf[SZ],*iS,*iT,c;int f,_eof;FILE*fi;
I(FILE*f):fi(f){}
inline char Gc(){return iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SZ,fi),(iS==iT?EOF:*iS++)):*iS++;}
inline ll operator()(){ll x;operator()(x);return x;}
inline I&operator()(char&x){x=Gc();return*this;}
inline I&operator()(char*s){for(c=Gc();c<32||c>126||c==' ';)c=Gc();for(;c>31&&c<127&&c!=' '&&c!='\n'&&c!='\r';++s,c=Gc())*s=c;*s=0;return*this;}
template<class T>inline I&operator()(T&x){_eof=0;for(f=1,c=Gc();(c<'0'||c>'9')&&!_eof;c=Gc()){if(c=='-')f=-1;_eof|=c==EOF;}for(x=0;c<='9'&&c>='0'&&!_eof;c=Gc())x=x*10+(c&15),_eof|=c==EOF;x*=f;return*this;}
template<class T>I&operator()(T*x,const int&n,const int&st=1){rep(i,st,n){operator()(x[i]);}return*this;}
} in(stdin);
struct O {
char obuf[SZ],*oS=obuf,*oT=oS+SZ-1,qu[55];int f,qr;FILE*fi;
O(FILE*f):fi(f){}
~O(){Flush();}
inline void Flush(){fwrite(obuf,1,oS-obuf,fi),oS=obuf;}
inline O&operator()(char x){*oS++=x;if(oS==oT)Flush();return*this;}
inline O&operator()(const char*s){int len=strlen(s);for(f=0;f<len;++f)operator()(s[f]);return*this;}
template<class T>inline O&operator()(T x){if(!x)operator()('0');if(x<0)operator()('-'),x=-x;while(x)qu[++qr]=x%10+'0',x/=10;while(qr)operator()(qu[qr--]);return*this;}
template<class T>O&operator()(T*x,const int&n,const char&ed=' ',const int&st=1){rep(i,st,n)operator()(x[i])(ed);return*this;}
} out(stdout);
}
using FastIO::in;using FastIO::out;
// #define int long long
// using namespace std;
int n,q;
int a[200005];
struct node{
int tim,lt,rt;
}Q[200005];
long long ans[200005];
int Block,num;
int st[200005];
int ed[200005];
int belone[200005];
int L[200005];
int stk[200005];
int top;
class rmq{
public:
int ST[200005][20];
int lg[200005];
void init(int a[],int n){
lg[0]=-1;
for(int i=1;i<=n;i++){
lg[i]=lg[i/2]+1;
}
for(int i=1;i<=n;i++){
ST[i][0]=a[i];
}
for(int j=1;j<=18;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
ST[i][j]=std::max(ST[i][j-1],ST[i+(1<<(j-1))][j-1]);
}
}
return;
}
int query(int lt,int rt){
int len=rt-lt+1;
return std::max(ST[lt][lg[len]],ST[rt-(1<<lg[len])+1][lg[len]]);
}
}P;
long long need[200005];
signed main(){
in(n)(q);
for(int i=1;i<=n;i++){
in(a[i]);
}
P.init(a,n);
for(int i=1;i<=q;i++){
int tim,lt,rt;
in(tim)(lt)(rt);
Q[i]=node{tim,lt,rt};
}
for(int i=n;i>=1;i--){
while(top&&a[stk[top]]<a[i]){
L[stk[top]]=i;
top--;
}
stk[++top]=i;
}
Block=sqrt(n);
num=(n+Block-1)/Block;
for(int i=1;i<=num;i++){
st[i]=(i-1)*Block+1;
ed[i]=std::min(i*Block,n);
for(int j=st[i];j<=ed[i];j++){
belone[j]=i;
}
}
for(int i=1;i<=num;i++){//处理第Block个块的答案,然后枚举每个询问录入答案。
for(int j=0;j<=n;j++)need[j]=0;
for(int k=st[i];k<=ed[i];k++){
int Max=0;
for(int j=0;j<=Block;j++){
if(k>j)Max=std::max(Max,a[k-j]);
need[j]+=Max;
}
}
int S=st[i],T=st[i]-1;
int Min=2e9,mini=-1;
for(int k=st[i];k<=ed[i];k++){
stk[++T]=P.query(std::max(k-Block,1),k);
}
int posL=-1,posR=-1;
for(int i=S;i<T;i++){
if(stk[i]<stk[i+1]){//以点i为谷底
posL=i,posR=i+1;
break;
}
}
if(posL==-1)posL=T,posR=T+1;
int seta=P.query(std::max(st[i]-Block,1),st[i]);
for(int j=Block+1;j<=n;j++){
if(j<st[i]){//仍在取用新的贡献点
seta=std::max(seta,a[st[i]-j]);
stk[--S]=seta;
}
//永远不丢掉第一个,如果最小值是第一个那就不做
need[j]=need[j-1];
if(posR>T){
if(posL==S){//不丢第一个
continue;
}
need[j]+=stk[S]-stk[posL--];
}
else{
if(stk[posL]<stk[posR]){
if(posL==S)continue;
need[j]+=stk[S]-stk[posL--];
}
else{
need[j]+=stk[S]-stk[posR++];
}
}
}
for(int j=1;j<=q;j++){
if(Q[j].lt<st[i]&&Q[j].rt>ed[i]){
ans[j]+=need[Q[j].tim];
}
}
//现在stk是单谷的,每次就会丢掉谷的权值,也就是最小值。
}
for(int i=1;i<=q;i++){
int lt=Q[i].lt,rt=Q[i].rt;
int L=belone[lt];
int R=belone[rt];
if(L==R){
for(int j=lt;j<=rt;j++){
ans[i]+=P.query(std::max(j-Q[i].tim,1),j);
}
continue;
}
for(int j=lt;j<=ed[L];j++){
ans[i]+=P.query(std::max(j-Q[i].tim,1),j);
}
for(int j=st[R];j<=rt;j++){
ans[i]+=P.query(std::max(j-Q[i].tim,1),j);
}
}
for(int i=1;i<=q;i++){
out(ans[i])('\n');
}
return 0;
}