題目大意
有一個神奇的大回環,由n塊石頭組成。
第i塊石頭有一個高度ai,兩塊不同的石頭i,j能夠互相看到,則它們在環上的兩條路徑中有至少一條路徑上除了兩個端點(即i,j)路徑上石頭高度都不大於min(ai,aj)。
求有多少對石頭能夠互相看到
數據範圍n<=1e6,T<=5,1<=ai<=1e9
先不考慮ai=aj的情況
我們可以把序列加倍,然後用單調棧處理出l[i]和r[i]
ai=aj時,這個討論起來不會很麻煩,處理l[i]的同時便可一起維護。
代碼
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define ll long long
using namespace std;
const int maxn=2e6+5;
int i,j,n,m,t,a[maxn],l[maxn],r[maxn],f[maxn];ll ans,an[maxn];
void read(int &x){
x=0;char c=getchar();
while ((c<'0')||(c>'9')) c=getchar();
while ((c>='0')&&(c<='9')) x=x*10+c-'0',c=getchar();
}
int main(){
freopen("forever.in","r",stdin);
freopen("forever.out","w",stdout);
read(t);
while (t>0){
t--;read(n);
fo(i,1,n+n) an[i]=0;
fo(i,1,n) read(a[i]),f[i]=i;
fo(i,n+1,n+n) a[i]=a[i-n];ans=0;
fo(i,1,n+n) {
j=i-1;
while ((j>0)&&(a[j]<=a[i])) {
if (a[j]==a[i]) {
if (i<=n) f[i]=f[j],an[f[i]]++,ans+=an[f[i]];else{
if (j<=n&&f[j]!=i-n) ans+=(ll)(an[f[j]]+1)*(an[f[i-n]]+1);
}
}
j=l[j];
}l[i]=j;
}
fod(i,n+n,1){
j=i+1;
while ((j<=(n+n))&&(a[j]<=a[i])) j=r[j];
r[i]=j;
}
fo(i,1,n) if (r[i]<=n+n) ans++;
fo(i,n+1,n+n) if (l[i]>0){
if (r[i-n]!=l[i])ans++;
}
printf("%lld\n",ans);
}
}