W
e
l
c
o
m
e
: )

题解:P4847 银河英雄传说V2

题意

给定 \(n\) 个长度为 \(1\) 的序列,第 \(i\) 个序列中有一个元素,值为 \(a_i\),接下来有三种操作:

  1. M x y,表示把 \(x\) 所在的序列放到 \(y\) 所在的序列之后。如果 \(x,y\) 已经在同一个序列,则不进行操作。
  2. D x,表示把 \(x\) 所在的序列中从 \(x\) 处断开,也就是把 \(x\)\(x\) 之后的元素单独取出来作为一个序列。
  3. Q x y,表示查询 \(x\)\(y\) 之间(包括 \(x\)\(y\))所有元素的值之和。如果 \(x\)\(y\) 不在同一个序列之中,输出 -1

分析

看到操作有分裂以及合并,考虑使用 FHQ Treap。

但是发现普通的 FHQ Treap 好像不支持按节点分裂。

所以我们对它进行一些修改,让节点额外维护它的父亲节点

考虑如何维护父亲节点。

我们可以在 push_up() 中维护父亲节点,将两个子节点的父节点设为自己。

node* push_up()
{
    siz=1;
    sum=v;
    if(lc) siz+=lc->siz, sum+=lc->sum, lc->fa=this;
    if(rc) siz+=rc->siz, sum+=rc->sum, rc->fa=this;
    return this;
}

但是分裂后的两根节点没有被更新,可能保存有错误的父节点指针。

分裂后或者合并后我们手动将它的父亲节点设为 \(0\) 即可。

维护了父亲节点,我们可以很容易地得到节点在中序遍历中的位置:

uint32_t find_pos(node *x)
{
    uint32_t res=siz(x->lc)+1;
    while(x->fa)
    {
        if(x->fa->rc==x) res+=siz(x->fa->lc)+1;
        x=x->fa;
    }
    return res;
}

同时也能快速找到根节点:

node *find_fa(node *x)
{
    while(x->fa) x=x->fa;
    return x;
}

剩下的操作就很简单了,都是 FHQ Treap 基本操作。

Code

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

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

    struct node
    {
        int64_t v;
        uint64_t id;
        int64_t siz=1;
        node *lc=0, *rc=0, *fa=0;
        int64_t add=0, sum=0;
        node(int va, uint64_t d): v(va), id(d) {sum=v;}

        void push_down()
        {
            if(!add) return;
            if(lc) lc->sum+=add*lc->siz, lc->add+=add, lc->v+=add;
            if(rc) rc->sum+=add*rc->siz, rc->add+=add, rc->v+=add;
            add=0;
        }

        node* push_up()
        {
            siz=1;
            sum=v;
            if(lc) siz+=lc->siz, sum+=lc->sum, lc->fa=this;
            if(rc) siz+=rc->siz, sum+=rc->sum, rc->fa=this;
            return this;
        }
    };

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

    #define siz(x) (x?x->siz:0)

    void split(node *x, int s, node *&l, node *&r)
    {
        if(!x) return l=r=0, void();
        x->push_down();
        if(siz(x->lc)<s) l=x, split(x->rc, s-siz(x->lc)-1, x->rc, r);
        else             r=x, split(x->lc, s, 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);
            return x->push_up();
        }
        else
        {
            y->push_down();
            y->lc=merge(x, y->lc);
            return y->push_up();
        }
    }

    node *find_fa(node *x)
    {
        while(x->fa) x=x->fa;
        return x;
    }

    
    uint32_t find_pos(node *x)
    {
        uint32_t res=siz(x->lc)+1;
        while(x->fa)
        {
            if(x->fa->rc==x) res+=siz(x->fa->lc)+1;
            x=x->fa;
        }
        return res;
    }
}

Treap::node *rt[maxn];

int main()
{
    int n, m;
    cin>>n>>m;
    for(int i=1, t;i<=n;i++) 
        cin>>t, rt[i]=Treap::new_node(t);
    while(m--)
    {
        char op;
        int x, y;
        cin>>op>>x;
        if(op=='M') 
        {
            cin>>y;
            auto fx=Treap::find_fa(rt[x]);
            auto fy=Treap::find_fa(rt[y]);
            if(fy==fx) continue;
            merge(fy, fx)->fa=0;
        }
        if(op=='D')
        {
            auto fx=Treap::find_fa(rt[x]);
            uint32_t rnk=Treap::find_pos(rt[x]);
            Treap::node *a, *b;
            Treap::split(fx, rnk-1, a, b);
            if(a) a->fa=0;
            if(b) b->fa=0;
        }
        if(op=='Q')
        {
            cin>>y;
            auto fx=Treap::find_fa(rt[x]);
            auto fy=Treap::find_fa(rt[y]);
            if(fx!=fy) cout<<-1<<'\n';
            else
            {
                uint32_t l=Treap::find_pos(rt[x]);
                uint32_t r=Treap::find_pos(rt[y]);
                if(l>r) swap(l, r);
                Treap::node *a, *b, *c;
                Treap::split(fx, l-1, a, b);
                Treap::split(b, r-l+1, b, c);
                int64_t ans=b->sum;
                merge(merge(a, b), c)->fa=0;
                cout<<ans<<'\n';
            }
        }
    }
}
posted @ 2024-08-25 21:03  Jimmy-LEEE  阅读(20)  评论(0)    收藏  举报