[XSY3383]多线程(笛卡尔树,DP)

%%% 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,p1,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[p1]划到 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[p1]一定要满足单调递增(这部分只能划到线程 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[p1]),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[p1]接起来)

用笛卡尔树实现。时间复杂度 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;
}

猜你喜欢

转载自blog.csdn.net/Emma2oo6/article/details/120587706