Range Sorting (Hard Version)
spider_oyster · · 题解
赛时想复杂了。当时只是想做出 B1,于是考虑
实际上这种题一般都是单个位置算贡献的。
先令答案为对所有区间“硬”排序的总贡献。
考虑位置为
那么
发现直接枚举不好算,我们可以钦定每个
- 实际是寻找满足上述式子的
l_{min} 和r_{max} ,那么区间数量就是(r_{max}-i+1)\times(x-l_{min}+1) 。- 可以发现,
x 是从i 往前第一个值小于a_i 的位置,否则a_i 一定不是[x+1,r] 的最小值。- 根据
\max\limits_{j=l}^{x}a_j<a_i ,从x 往前找l_{min} 即可。- 根据
a_i 是[x+1,r] 的最小值,r_{max} 是从i 往后第一个值小于a_i 的往前一个位置,否则a_i 一定不是[x+1,r] 的最小值。
由于
所以这道题难就难在想到用钦定最小值的方法来计算。
对于形如“第一个大于/小于”,可以用单调栈求。
对于
时间复杂度
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
int n,t,a[N],f[20][N],r[N];
long long ans;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>t;
while(t--)
{
ans=0;
cin>>n;
a[0]=a[n+1]=0;
for(int i=1;i<=n;i++) cin>>a[i],f[0][i]=a[i],ans+=1ll*i*(i-1)/2;
for(int j=1;j<20;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
f[j][i]=max(f[j-1][i],f[j-1][i+(1<<j-1)]);
stack<int> st;
st.push(n+1);
for(int i=n;i;i--)
{
//这里求的实际是 r_min+1,从后往前第一个小于 a[i] 的位置
while(a[st.top()]>a[i]) st.pop();
r[i]=st.top();
st.push(i);
}
while(!st.empty()) st.pop();
st.push(0);
for(int i=1;i<=n;i++)
{
//这里求的是 x
while(a[st.top()]>a[i]) st.pop();
int j=st.top();
//跳表求 l_min
for(int k=19;~k;k--)
if(j>(1<<k)&&f[k][j-(1<<k)]<a[i]) j-=1<<k;
if(st.top()>0) ans-=1ll*(r[i]-i)*(st.top()-j+1);
st.push(i);
}
cout<<ans<<'\n';
}
}