笛卡尔树

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 }
POJ2559

 

以上是关于笛卡尔树的主要内容,如果未能解决你的问题,请参考以下文章

[模板]笛卡尔树

(王道408考研数据结构)第六章图-第四节2:最小生成树之克鲁斯卡尔算法(思想代码演示答题规范)

最小生成树 普里姆算法和克鲁斯卡尔算法

克鲁斯卡尔算法

笛卡尔树

笛卡尔树