2500分的题还是不会做,菜哭.jpg,看了网上题解,觉得十分精妙
其实f(l,r)相当于一个不断删数字然后求产生的价值和的过程,设第i个数字左边第一个比他大的数字为第lind[i]个数字,右边的为第rind[i]个,那么删掉第i个数字,留下左右两边的数字,所产生的价值就是(rind[i]-1)-(lind[i]+1)+1,也就是这一段的长度。
吧询问离线,然后分两段计算,这样就不会重复计算,导致出错
我们先计算从每个数字的lind[i]+1到第i个这一段的代价,从左到有扫一遍,扫到i,就把lind[i]+1到i全部加1,lq[i]这里有一个询问,也就是询问lq[i][j]到i的价值,由于我们从左到右,所以此时lq[i][j]到i已经全部用线段树求值出来了。
再计算从i+1到rind[i]-1这一段的价值,从右向左扫,然后加到从i到rq[i][j]这一段的询问的答案中
#include<bits/stdc++.h>
#define maxl 1000010
#define mp make_pair
#define pb push_back
using namespace std;
struct node
{
int l,r;
long long sum,tag;
}tree[maxl<<2];
int n,q,len,top;
int a[maxl],lind[maxl],rind[maxl],s[maxl],l[maxl],r[maxl];
typedef pair<int,int> p;
vector <p> lq[maxl],rq[maxl];
long long ans[maxl];
inline void prework()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
a[0]=a[n+1]=2*1e9;
top=0;s[++top]=0;
for(int i=1;i<=n;i++)
{
while(a[i]>a[s[top]] && top>0)
top--;
s[++top]=i;lind[i]=s[top-1];
}
top=0;s[++top]=n+1;
for(int i=n;i>=1;i--)
{
while(a[i]>a[s[top]] && top>0)
top--;
s[++top]=i;rind[i]=s[top-1];
}
for(int i=1;i<=q;i++)
scanf("%d",&l[i]);
for(int i=1;i<=q;i++)
scanf("%d",&r[i]);
for(int i=1;i<=q;i++)
{
lq[r[i]].pb(mp(l[i],i));
rq[l[i]].pb(mp(r[i],i));
}
}
inline void build(int k,int l,int r)
{
tree[k].l=l;tree[k].r=r;tree[k].sum=0;tree[k].tag=0;
if(l==r)
return;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
inline long long query(int k,int l,int r)
{
if(tree[k].l==l && tree[k].r==r)
return tree[k].sum;
int mid=(tree[k].l+tree[k].r)>>1;
long long res=(r-l+1)*tree[k].tag;
if(r<=mid)
res+=query(k<<1,l,r);
else if(l>mid)
res+=query(k<<1|1,l,r);
else
res+=query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
return res;
}
inline void add(int k,int l,int r,int val)
{
tree[k].sum+=(r-l+1)*val;
if(tree[k].l==l &&tree[k].r==r)
{
tree[k].tag+=val;
return;
}
int mid=(tree[k].l+tree[k].r)>>1;
if(r<=mid)
add(k<<1,l,r,val);
else if(l>mid)
add(k<<1|1,l,r,val);
else
add(k<<1,l,mid,val),add(k<<1|1,mid+1,r,val);
//tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
inline void mainwork()
{
int len;
build(1,1,n);
for(int i=1;i<=n;i++)
{
add(1,lind[i]+1,i,1);
len=lq[i].size();
for(int j=0;j<len;j++)
ans[lq[i][j].second]+=query(1,lq[i][j].first,i);
}
build(1,1,n);
for(int i=n;i>=1;i--)
{
if(i+1<=rind[i]-1)
add(1,i+1,rind[i]-1,1);
len=rq[i].size();
for(int j=0;j<len;j++)
ans[rq[i][j].second]+=query(1,i,rq[i][j].first);
}
}
inline void print()
{
for(int i=1;i<=q;i++)
printf("%lld ",ans[i]);
}
int main()
{
prework();
mainwork();
print();
return 0;
}