%%% t j y tjy tjy的笛卡尔树做法:
设 d p ( l , r , A m i n , B m i n ) dp(l,r,Amin,Bmin) dp(l,r,Amin,Bmin)为把 c [ l ] , c [ l + 1 ] , . . . , c [ r ] c[l],c[l+1],...,c[r] c[l],c[l+1],...,c[r]划到 A , B A,B A,B两线程中,且划到 A A A线程的数 > A m i n >Amin >Amin,划到 B B B线程的数 > B m i n >Bmin >Bmin的方案数。
我们找到 p p p,满足 c [ p ] = m a x { c [ l ] , c [ l + 1 ] , . . . , c [ r ] } c[p]=max\{c[l],c[l+1],...,c[r]\} c[p]=max{ c[l],c[l+1],...,c[r]}。发现 p p p只可能是单增栈 A A A的末尾 或 单减栈 B B B的开头。
-
若 p p p是单增栈 A A A的末尾:
那么 c [ p + 1 ] , c [ p + 2 ] , . . . , c [ r ] c[p+1],c[p+2],...,c[r] c[p+1],c[p+2],...,c[r]一定要满足单调递减(这部分只能划到线程 B B B),若满足则有 d p ( l , r , A m i n , B m i n ) ← d p ( l , p − 1 , A m i n , m a x ( B m i n , c [ p + 1 ] ) ) dp(l,r,Amin,Bmin)\leftarrow dp(l,p-1,Amin,max(Bmin,c[p+1])) dp(l,r,Amin,Bmin)←dp(l,p−1,Amin,max(Bmin,c[p+1]))
( c [ l ] , c [ l + 1 ] , . . . , c [ p − 1 ] c[l],c[l+1],...,c[p-1] c[l],c[l+1],...,c[p−1]划到 B B B线程的部分,要和划到 B B B线程的 c [ p + 1 ] , c [ p + 2 ] , . . . , c [ r ] c[p+1],c[p+2],...,c[r] c[p+1],c[p+2],...,c[r]接起来) -
若 p p p是单减栈 B B B的开头:
那么 c [ l ] , c [ l + 1 ] , . . . , c [ p − 1 ] c[l],c[l+1],...,c[p-1] c[l],c[l+1],...,c[p−1]一定要满足单调递增(这部分只能划到线程 A A A),若满足则有 d p ( l , r , A m i n , B m i n ) ← d p ( p + 1 , r , m a x ( A m i n , c [ p − 1 ] ) , B m i n ) dp(l,r,Amin,Bmin)\leftarrow dp(p+1,r,max(Amin,c[p-1]),Bmin) dp(l,r,Amin,Bmin)←dp(p+1,r,max(Amin,c[p−1]),Bmin)
( c [ p + 1 ] , c [ p + 2 ] , . . . , c [ r ] c[p+1],c[p+2],...,c[r] c[p+1],c[p+2],...,c[r]划到 A A A线程的部分,要和划到 A A A线程的 c [ l ] , c [ l + 1 ] , . . . , c [ p − 1 ] c[l],c[l+1],...,c[p-1] c[l],c[l+1],...,c[p−1]接起来)
用笛卡尔树实现。时间复杂度 O ( n ) O(n) O(n)。
#include<bits/stdc++.h>
const int N=500010;
const int inf=0x7fffffff;
using namespace std;
int t,n,a[N],minn[N];
int top,sta[N],rt,ls[N],rs[N];
bool up[N],down[N];
void init(int u){
if(!u) return;
init(ls[u]),init(rs[u]);
minn[u]=min(a[u],min(minn[ls[u]],minn[rs[u]]));
up[u]=up[ls[u]]&&(!rs[u]);
down[u]=down[rs[u]]&&(!ls[u]);
}
int dfs(int u,int Amin,int Bmin){
if(!u) return 1;
int ans=0;
if(up[ls[u]]&&minn[ls[u]]>Amin&&a[u]>Bmin)
ans+=dfs(rs[u],ls[u]?a[ls[u]]:Amin,Bmin);
if(down[rs[u]]&&minn[rs[u]]>Bmin&&a[u]>Amin)
ans+=dfs(ls[u],Amin,rs[u]?a[rs[u]]:Bmin);
return ans;
}
int main(){
minn[0]=inf;
up[0]=down[0]=1;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
int maxn=-inf;
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
if(a[i]>maxn) maxn=a[i],rt=i;
ls[i]=rs[i]=0;
}
top=0;
for(int i=1;i<=n;i++){
while(top&&a[sta[top]]<a[i]){
ls[i]=sta[top];top--;}
if(top) rs[sta[top]]=i;
sta[++top]=i;
}
init(rt);
printf("%d\n",dfs(rt,-inf,-inf));
}
return 0;
}