[XSY3383]多线程(笛卡尔树,DP)
%%%tjytjytjy的笛卡爾樹做法:
設(shè)dp(l,r,Amin,Bmin)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,BA,BA,B兩線程中,且劃到AAA線程的數(shù)>Amin>Amin>Amin,劃到BBB線程的數(shù)>Bmin>Bmin>Bmin的方案數(shù)。
我們找到ppp,滿足c[p]=max{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]}。發(fā)現(xiàn)ppp只可能是單增棧AAA的末尾 或 單減棧BBB的開頭。
-
若ppp是單增棧AAA的末尾:
那么c[p+1],c[p+2],...,c[r]c[p+1],c[p+2],...,c[r]c[p+1],c[p+2],...,c[r]一定要滿足單調(diào)遞減(這部分只能劃到線程BBB),若滿足則有dp(l,r,Amin,Bmin)←dp(l,p?1,Amin,max(Bmin,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]劃到BBB線程的部分,要和劃到BBB線程的c[p+1],c[p+2],...,c[r]c[p+1],c[p+2],...,c[r]c[p+1],c[p+2],...,c[r]接起來) -
若ppp是單減棧BBB的開頭:
那么c[l],c[l+1],...,c[p?1]c[l],c[l+1],...,c[p-1]c[l],c[l+1],...,c[p?1]一定要滿足單調(diào)遞增(這部分只能劃到線程AAA),若滿足則有dp(l,r,Amin,Bmin)←dp(p+1,r,max(Amin,c[p?1]),Bmin)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]劃到AAA線程的部分,要和劃到AAA線程的c[l],c[l+1],...,c[p?1]c[l],c[l+1],...,c[p-1]c[l],c[l+1],...,c[p?1]接起來)
用笛卡爾樹實現(xiàn)。時間復(fù)雜度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; }總結(jié)
以上是生活随笔為你收集整理的[XSY3383]多线程(笛卡尔树,DP)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [XSY3382] 专家系统(二分+线段
- 下一篇: 因释其耒而守株是什么意思 因释其耒而守株