zoukankan      html  css  js  c++  java
  • 笛卡尔树

    笛卡尔树的节点具有两个属性:键值与权值。

    中序遍历每个节点,则其键值递增。任意一个父亲的权值都一定大于(小于)其儿子的权值。

    由此可知,笛卡尔树的键值具有二叉搜索树的性质,权值具有堆的性质。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
    ",ans);
    30     }
    31     return 0;
    32 }
    POJ2559

    2.[BZOJ5042]LWD的分科岛

    用LCA做到$O(nalpha(n))$实现RMQ。

    以求区间最小值为例,先建出小根笛卡尔树,当询问[l,r]时,找到l,r对应的点,它们的LCA的权值就是[l,r]的最小值。

    Tarjan离线实现LCA即可。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=3000010;
     7 int n,m,cnt,top1,top2,rt1,rt2,op,l,r,h[2][N],val[N],to[N<<1],nxt[N<<1];
     8 int vis[N],a[N],stk1[N],stk2[N],fa[N],ans[N],son[2][N][2];
     9 
    10 int get(int x){ return fa[x]==x ? x : fa[x]=get(fa[x]); }
    11 void add(int k,int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[k][u]; h[k][u]=cnt; }
    12 
    13 int rd(){
    14     int x=0; char ch=getchar(); bool f=0;
    15     while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar();
    16     while (ch>='0' && ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    17     return f ? -x : x;
    18 }
    19 
    20 void Tarjan(int x,int k){
    21     vis[x]=1;
    22     if (son[k][x][0]) Tarjan(son[k][x][0],k),fa[son[k][x][0]]=get(x);
    23     if (son[k][x][1]) Tarjan(son[k][x][1],k),fa[son[k][x][1]]=get(x);
    24     for (int i=h[k][x]; i; i=nxt[i]){
    25         int z=to[i],id=val[i];
    26         if (vis[z]) ans[id]=a[get(z)];
    27     }
    28 }
    29 
    30 int main(){
    31     freopen("bzoj5042.in","r",stdin);
    32     freopen("bzoj5042.out","w",stdout);
    33     n=rd(); m=rd();
    34     rep(i,1,n) a[i]=rd();
    35     rep(i,1,n){
    36         while (top1 && a[stk1[top1]]>a[i]) son[0][i][0]=stk1[top1--];
    37         if (top1) son[0][stk1[top1]][1]=i;
    38         stk1[++top1]=i;
    39         while (top2 && a[stk2[top2]]<a[i]) son[1][i][0]=stk2[top2--];
    40         if (top2) son[1][stk2[top2]][1]=i;
    41         stk2[++top2]=i;
    42     }
    43     rt1=stk1[1]; rt2=stk2[1];
    44     rep(i,1,m){
    45         op=rd(); l=rd(); r=rd();
    46         if (op==1) add(0,l,r,i),add(0,r,l,i); else add(1,l,r,i),add(1,r,l,i);
    47     }
    48     rep(i,1,n) fa[i]=i; Tarjan(rt1,0);
    49     rep(i,1,n) fa[i]=i; Tarjan(rt2,1);
    50     rep(i,1,m) printf("%d
    ",ans[i]);
    51     return 0;
    52 }
    BZOJ5042

    3.[ICPC 2016 Hong Kong]G.Scanffolding

    https://blog.gyx.me/note/cartesiantree.pdf

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define ls son[x][0]
     4 #define rs son[x][1]
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 typedef long long ll;
     7 using namespace std;
     8 
     9 const int N=100010;
    10 int n,m,top,a[N],son[N][2],stk[N];
    11 ll sm[N],f[N],g[N];
    12 
    13 int dfs(int x,int fa){
    14     if (!x) return 0;
    15     int w=dfs(ls,x)+dfs(rs,x)+1;
    16     sm[x]=a[x]+sm[ls]+sm[rs];
    17     ll r=1ll*(a[x]-a[fa])*w-(g[ls]+g[rs]);
    18     f[x]=f[ls]+f[rs]+max(0ll,(r+m-1)/m);
    19     g[x]=f[x]*m-(sm[x]-1ll*a[fa]*w);
    20     return w;
    21 }
    22 
    23 int main(){
    24     freopen("scanffolding.in","r",stdin);
    25     freopen("scanffolding.out","w",stdout);
    26     scanf("%d%d",&n,&m);
    27     rep(i,1,n) scanf("%d",&a[i]);
    28     rep(i,1,n){
    29         while (top && a[stk[top]]>a[i]) son[i][0]=stk[top--];
    30         son[stk[top]][1]=i; stk[++top]=i;
    31     }
    32     dfs(stk[1],0); printf("%lld
    ",f[stk[1]]);
    33     return 0;
    34 }
    Scanffolding

    4.[BZOJ2616]SPOJ PERIODNI

    与上题类似,搞清这个思想后DP方程就是很显然的了。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=510,M=1000010,mod=1e9+7;
     9 int n,m,tot,top,f[N][N],fac[M],inv[M],g[N],stk[N],fa[N],a[N],son[N][2];
    10 
    11 int C(int n,int m){ return n<m ? 0 : 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod; }
    12 
    13 int ksm(int a,int b){
    14     int res=1;
    15     for (; b; a=1ll*a*a%mod,b>>=1)
    16         if (b & 1) res=1ll*res*a%mod;
    17     return res;
    18 }
    19 
    20 void init(int n){
    21     fac[0]=inv[0]=1;
    22     rep(i,1,n) fac[i]=1ll*fac[i-1]*i%mod;
    23     inv[n]=ksm(fac[n],mod-2);
    24     for (int i=n-1; i; i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
    25 }
    26 
    27 int dfs(int x){
    28     int s=1,b=a[x]-a[fa[x]]; f[x][0]=1;
    29     rep(i,0,1) if (son[x][i]){
    30         int y=son[x][i],d=dfs(y); memset(g,0,sizeof(g));
    31         rep(j,0,s) rep(k,0,min(d,m-j)) g[j+k]=(g[j+k]+1ll*f[x][j]*f[y][k])%mod;
    32         s+=d; rep(j,0,s) f[x][j]=g[j];
    33     }
    34     for (int i=min(m,s); ~i; i--){
    35         int t=0;
    36         rep(j,0,i) t=(t+1ll*f[x][i-j]*fac[j]%mod*C(s-i+j,j)%mod*C(b,j))%mod;
    37         f[x][i]=t;
    38     }
    39     return s;
    40 }
    41 
    42 int main(){
    43     freopen("bzoj2616.in","r",stdin);
    44     freopen("bzoj2616.out","w",stdout);
    45     scanf("%d%d",&n,&m); init(1000000);
    46     rep(i,1,n) scanf("%d",&a[i]);
    47     rep(i,1,n){
    48         while (top && a[stk[top]]>a[i]) son[i][0]=stk[top--];
    49         if (top) son[stk[top]][1]=i,fa[i]=stk[top];
    50         stk[++top]=i; if (son[i][0]) fa[son[i][0]]=i;
    51     }
    52     dfs(stk[1]); printf("%d
    ",f[stk[1]][m]);
    53     return 0;
    54 }
    BZOJ2616
  • 相关阅读:
    一些浏览器的兼容和雪碧图的使用
    常用的一些样式
    Open.auth 开源项目学习(一)SSO单点登录
    一个开发人员对于职业生涯规划的感想
    从今天开始分享自己的学习经历
    mysql在海量数据时的处理方案
    Mysql分区
    su和sudo的区别
    su:authentication failure问题
    大数据处理思路
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10620518.html
Copyright © 2011-2022 走看看