笛卡尔树
Posted hocriser
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了笛卡尔树相关的知识,希望对你有一定的参考价值。
笛卡尔树的节点具有两个属性:键值与权值。
中序遍历每个节点,则其键值递增。任意一个父亲的权值都一定大于(小于)其儿子的权值。
由此可知,笛卡尔树的键值具有二叉搜索树的性质,权值具有堆的性质。Treap就是实现了一棵笛卡尔树。
笛卡尔树一般是根据序列建立的,一般以序列下标为键值,序列中的数为权值。
它的建立与虚树相似,从左到右将序列中的点依次插入树中,维护树的右链即可轻松实现。
一般来说,笛卡尔树中的一个点代表的是一段位置,这段位置就是中序遍历这个点的子树得到的那段连续区间(下面叫它管辖范围),在DP中也可能代表当前这个位置所在的极大矩形。
下面是几个简单的应用:
1.[POJ2559]Largest Rectangle in a Histogram
给一张图求出其中最大的矩形。
这是一道单调栈模板题,考虑笛卡尔树的做法。
注意到答案就是每个点的管辖范围宽度乘上这个点的权值h[]。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=100010; 8 ll ans; 9 int n,top,rt,a[N],w[N],stk[N],son[N][2]; 10 11 void dfs(int x,int L,int R){ 12 w[x]=R-L+1; ans=max(ans,1ll*w[x]*a[x]); 13 if (son[x][0]) dfs(son[x][0],L,x-1); 14 if (son[x][1]) dfs(son[x][1],x+1,R); 15 } 16 17 int main(){ 18 freopen("poj2559.in","r",stdin); 19 freopen("poj2559.out","w",stdout); 20 while (scanf("%d",&n),n){ 21 rep(i,1,n) scanf("%d",&a[i]); 22 top=0; 23 rep(i,1,n) son[i][0]=son[i][1]=0; 24 rep(i,1,n){ 25 while (top && a[stk[top]]>a[i]) son[i][0]=stk[top--]; 26 if (top) son[stk[top]][1]=i; 27 stk[++top]=i; 28 } 29 rt=stk[1]; ans=0; dfs(rt,1,n); printf("%lld\n",ans); 30 } 31 return 0; 32 }
以上是关于笛卡尔树的主要内容,如果未能解决你的问题,请参考以下文章