笛卡尔树小结

粗略的学习了一下笛卡尔树 主要是为了平衡树打基础吧 因为关于平衡树 treap 早忘了 splay 不信任复杂度 然后 我能学一种比较简单的树Y

笛卡尔树.这里以建出小根堆为例。描述区间性质的树 可以当成二叉搜索树不过并不平衡因为每次都是选取当前区间最小值当做为根 然后显然根据区间的数的排列不同树的形态也不相同。

所以查找 插入等操作显然不适合它 。能做什么?(我也不知道23333...应该有一定的作用 比如说可以求...

卡尔树中的一个点代表的是一段位置,这段位置就是中序遍历这个点的子树得到的那段连续区间...

过多我也不会了 也不敢口胡挺简单的一个东西。qwq

其实就是这个东西 考虑怎么构造出来一个比较简单的做法是 单调栈 维护整棵树的右链轻松完成构造 复杂度O(n)

还有其他的构造方法最简单的就是递归构造法每次暴力扫描最小的那个数字 然后qwq.. 复杂度O(n^2)

还有 递归构造的时候 考虑线段树维护区间最小值 于是复杂度降到了 nlogn。。

这里推荐直接O(n)非常简单比线段树不知道高到哪里去了。

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define ll long long
#define INF 1000000000
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define us unsigned
#define mod 1000000007
#define db double
using namespace std;
const int MAXN=100010;
int n,rt,top;
ll ans;
int a[MAXN];
int st[MAXN],s[MAXN][2],f[MAXN];
inline void dfs(int x,int l,int r)
{
    ll sz=r-l+1;
    ans=max(ans,sz*a[x]);
    if(s[x][0])dfs(s[x][0],l,x-1);
    if(s[x][1])dfs(s[x][1],x+1,r);
}
int main()
{
    freopen("1.in","r",stdin);
    while(1)
    {
        scanf("%d",&n);ans=0;
        if(!n)break;
        top=ans=0;
        for(int i=1;i<=n;++i)scanf("%d",&a[i]),f[i]=s[i][0]=s[i][1]=0;
        for(int i=1;i<=n;++i)
        {
            while(top&&a[st[top]]>a[i])s[i][0]=st[top--];
            if(top)f[i]=st[top],s[st[top]][1]=i;
            st[++top]=i;
        }
        rt=st[1];dfs(rt,1,n);printf("%lld
",ans);
    }
    return 0;
}
View Code

 说好了  要写题的qwq

LINK:beautiful pair 数点 又见数点 每次遇到数点问题 都是树状数组或者主席数具体的此题我以前模拟赛做过qwq

我用的是单调栈和主席树(笛卡尔树什么的都是浮云qwq原理差不多 关键是暴力扫 可以证明 然后主席树快速数点即可。

可以证明暴力扫的复杂度是nlog的 所以总复杂度 nlognlogn 所以可以通过本题。

值得一提的是查询的时候注意边界 不然会TLE 值得一提的是不需要离散 感觉会更慢一点qwq.

//#include<bits/stdc++.h>
#include<iostream>
#include<queue>
#include<iomanip>
#include<cctype>
#include<cstdio>
#include<deque>
#include<utility>
#include<cmath>
#include<ctime>
#include<cstring>
#include<string>
#include<cstdlib>
#include<vector>
#include<algorithm>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#define INF 1000000000
#define ll long long
#define db double
#define pb push_back
#define un unsigned
#define l(p) t[p].l
#define r(p) t[p].r
#define sum(p) t[p].sum
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
    return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
}
const int MAXN=100010;
int n,cnt;
int minn=INF,maxx,top;
int root[MAXN],s[MAXN],a[MAXN],L[MAXN],R[MAXN];
struct wy
{
    int l,r;
    int sum;
}t[MAXN*30<<1];
ll ans;
inline void insert(int &p,int last,int l,int r,int x)
{
    p=++cnt;t[p]=t[last];
    if(l==r){sum(p)+=1;return;}
    int mid=(l+r)>>1;
    if(x<=mid)insert(l(p),l(last),l,mid,x);
    else insert(r(p),r(last),mid+1,r,x);
    sum(p)=sum(l(p))+sum(r(p));
}
inline int ask(int p,int lp,int l,int r,int w)
{
    if(r<=w)return sum(p)-sum(lp);
    int mid=(l+r)>>1;
    if(w<=mid)return ask(l(p),l(lp),l,mid,w);
    else return ask(r(p),r(lp),mid+1,r,w)+ask(l(p),l(lp),l,mid,w);
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();
    for(int i=1;i<=n;++i)
    {
        a[i]=read();
        minn=min(minn,a[i]);
        maxx=max(maxx,a[i]);
    }
    for(int i=1;i<=n;++i)
        insert(root[i],root[i-1],minn,maxx,a[i]);
    s[top=1]=0;a[0]=INF+1;
    for(int i=1;i<=n;++i)
    {
        while(a[s[top]]<=a[i])--top;
        L[i]=s[top]+1;s[++top]=i;
    }
    s[top=1]=n+1;a[n+1]=INF+1;
    for(int i=n;i;--i)
    {
        while(a[s[top]]<a[i])--top;
        R[i]=s[top]-1;s[++top]=i;
    }
    for(int i=1;i<=n;++i)
    {
        if(i-L[i]<R[i]-i)//扫区间较小的一段
        {
            for(int j=L[i];j<=i;++j)
            {
                int w=a[i]/a[j];
                if(w>=minn)ans+=ask(root[R[i]],root[i-1],minn,maxx,w);
            }
        }
        else
        {
            for(int j=R[i];j>=i;--j)
            {
                int w=a[i]/a[j];
                if(w>=minn)ans+=ask(root[i],root[L[i]-1],minn,maxx,w);
            }
        }
    }
    printf("%lld
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/chdy/p/11702779.html