笛卡爾樹小結

粗略的學習了一下笛卡爾樹 主要是爲了平衡樹打基礎吧 由於關於平衡樹 treap 早忘了 splay 不信任複雜度 而後 我能學一種比較簡單的樹Yios

笛卡爾樹.這裏以建出小根堆爲例。描述區間性質的樹 能夠當成二叉搜索樹不過並不平衡由於每次都是選取當前區間最小值當作爲根 而後顯然根據區間的數的排列不一樣樹的形態也不相同。c++

因此查找 插入等操做顯然不適合它 。能作什麼?(我也不知道23333...應該有必定的做用 好比說能夠求...數組

卡爾樹中的一個點表明的是一段位置,這段位置就是中序遍歷這個點的子樹獲得的那段連續區間...ide

過多我也不會了 也不敢口胡挺簡單的一個東西。qwq學習

其實就是這個東西 考慮怎麼構造出來一個比較簡單的作法是 單調棧 維護整棵樹的右鏈輕鬆完成構造 複雜度O(n)spa

還有其餘的構造方法最簡單的就是遞歸構造法每次暴力掃描最小的那個數字 而後qwq.. 複雜度O(n^2)code

還有 遞歸構造的時候 考慮線段樹維護區間最小值 因而複雜度降到了 nlogn。。blog

這裏推薦直接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\n",ans);
    }
    return 0;
}
View Code

 說好了  要寫題的qwqip

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\n",ans);
    return 0;
}
View Code
相關文章
相關標籤/搜索