W
e
l
c
o
m
e
: )

题解:CF1290E Cartesian Tree

题意

给定一个 \(1\sim n\) 的排列 \(a\)

对于一个整数 \(k\in[1,n]\),将排列中 \(\leqslant k\) 的项构成的子序列建大根笛卡尔树。这棵笛卡尔树的所有节点的子树大小之和记为 \(s_k\)

\(\forall k\in[1,n]\)\(s_k\)

分析

首先看到题目要求维护 \(s_k\),但是这个东西和笛卡尔树的性质没什么关系。

考虑将 \(s_k\) 拆成多个信息。

根据笛卡尔树的性质,我们知道 \(s_i\) 就是子序列上以 \(i\) 为最大值的极大区间 \([l_i, r_i]\) 的长度。

意味着 \(l_i-1\) 等于 \(0\) 或其权值 \(val_{l_i-1}>i\)

另一侧同理。

因为 \(s_i=r_i-l_i+1\),所以我们维护左右端点 \(l_i,r_i\)

答案为 \(\sum_{i=1}^k\limits s_i = \sum_{i=1}^k\limits r_i - l_i + 1\)


我们考虑如何维护 \(l_i\)\(r_i\)

这里以 \(r_i\) 为例。

先想一下子序列形成的过程,我们可以想成向一个序列中每次插入值,然后再查询。

有个显然的性质:每次插入的值是插入后序列的最大值。

我们将子序列沿插入位置 \(p\) 拆成两个区间 \([1,p-1]\)\([p+1, k]\)

对于 \(i \in [1, p-1]\),因为值一定小于新插入的值,所以其右端点 \(r_i\) 一定也在区间 \([1,p-1]\) 中。

所以 \(r_i \gets \min(r_i,p-1)\)

而对于 \(i \in [p+1, k]\),它们的 \(r_i\) 和新插入的值无关,只是增加了 \(1\)

\(l_i\) 的想法差不多,二者维护方式如下:

\[\begin{align} r_i & \gets \begin{cases} \min(r_i, p-1) & i\in [1,p-1] \\ r_i+1 & i\in[p+1,k] \end{cases} \\ l_i &\gets \begin{cases} l_i & i\in [1,p-1] \\ \max(p+1, l_i+1) & i\in[p+1,k] \end{cases} \end{align} \]

新插入的值作为序列的最大值,其子树就是整棵树,所以 \(l_p \gets 1,r_p\gets k\)


所以我们只需要写一个数据结构支持以下四种操作:

  • 单点插入一个值。
  • 区间加。
  • 区间取 \(\min\)\(\max\)
  • 查询和。

直接上平衡树。


写能维护 \(\min\)\(\max\) 的平衡树码量有点大,可以只写能维护 \(\min\) 的平衡树。

这时维护的就是 \(r_i\)\(-l_i\)

Code

#include<bits/stdc++.h>
using namespace std;

namespace Base_Treap
{
    mt19937 rnd(time(0));

    #define mx(x) (x?x->mx:-INT_MAX)
    #define smx(x) (x?x->smx:-INT_MAX)
    #define siz(x) (x?x->siz:0)

    struct node
    {
        uint32_t siz;
        uint64_t id;
        node *lc, *rc;
        int mx, smx, cnt, tag1, tag2, val;
        int64_t sum;

        node(int v, uint64_t idd) {sum=mx=val=v, lc=rc=0, siz=cnt=1, id=idd, smx=-INT_MAX, tag1=0; tag2=-INT_MAX;}
    
        void push_up()
        {
            sum=val;siz=1;
            if(lc) sum+=lc->sum, siz+=lc->siz;
            if(rc) sum+=rc->sum, siz+=rc->siz;
            mx=max({val, mx(lc), mx(rc)});
            smx=max(smx(lc), smx(rc));
            cnt=0;
            if(mx==val) cnt++;
            else smx=max(smx, val);
            if(mx==mx(lc)) cnt+=lc->cnt;
            else smx=max(smx, mx(lc));
            if(mx==mx(rc)) cnt+=rc->cnt;
            else smx=max(smx, mx(rc));
        }

        void add(int v) 
        {
            sum+=1ll*v*siz;
            mx+=v;
            val+=v;
            if(smx!=-INT_MAX) smx+=v;
            if(tag2!=-INT_MAX) tag2+=v;
            tag1+=v; 
        }

        void do_min(int v)
        {
            if(v>=mx) return;
            sum-=1ll*(mx-v)*cnt;
            val=min(val, v);
            tag2=mx=v;
        }

        void push_down()
        {
            if(tag1)
            {
                if(lc) lc->add(tag1);
                if(rc) rc->add(tag1);
                tag1=0;
            }
            if(tag2!=-INT_MAX)
            {
                if(lc) lc->do_min(tag2);
                if(rc) rc->do_min(tag2);
                tag2=-INT_MAX;
            }
        }

        void modify(int x)
        {
            if(mx<=x) return;
            if(smx<x) return do_min(x);
            push_down();
            if(val>x) sum-=val-x, val=x;
            if(lc) lc->modify(x);
            if(rc) rc->modify(x);
            push_up();
        }
    };

    node* new_node(int x) {return new node(x, rnd());}

    void split(node *x, uint32_t k, node *&l, node *&r)
    {
        if(!x) return l=r=0, void();
        x->push_down();
        if(k>siz(x->lc)) l=x, split(x->rc, k-siz(x->lc)-1, x->rc, r);
        else             r=x, split(x->lc, k, l, x->lc);
        x->push_up();
    }

    node* merge(node *x, node *y)
    {
        if(!x||!y) return x?x:y;
        if(x->id>y->id)
        {
            x->push_down();
            x->rc=merge(x->rc, y);
            x->push_up();
            return x;
        }
        else
        {
            y->push_down();
            y->lc=merge(x, y->lc);
            y->push_up();
            return y;
        }
    }
}

using namespace Base_Treap;

node *rtl=0, *rtr=0;

void modify_r(int p, int v)
{
    node *a, *b;
    split(rtr, p, a, b);
    if(a) a->modify(p);
    if(b) b->add(1);
    rtr=merge(a, merge(new_node(v), b));
}

void modify_l(int p)
{
    node *a, *b;
    split(rtl, p, a, b);
    if(b) b->add(-1), b->modify(-p-2);
    rtl=merge(a, merge(new_node(-1), b));
}

int a[150005], pos[150005];

struct BIT: vector<int>
{
    using vector<int>::vector;
    void modify(int p) {for(;p<size();p+=p&-p) at(p)++;} 
    int query(int p) {int r=0;for(;p;p-=p&-p) r+=at(p); return r;}
}ta(150005);

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i], pos[a[i]]=i;
    for(int i=1;i<=n;i++)
    {
        int np=ta.query(pos[i]);
        ta.modify(pos[i]);
        modify_l(np);
        modify_r(np, i);
        cout<<rtr->sum+rtl->sum+i<<'\n';
    }
}
posted @ 2024-08-25 20:59  Jimmy-LEEE  阅读(31)  评论(0)    收藏  举报