【HDU 6973】Bookshop 树剖+平衡树

【引言】

​ 平衡树的题做得比较少,难得补一次神题,记录一下供以后学习。

【题意】

​ 给出一棵 个结点的树,每个结点有一个价值为 的商品。

​ 有 次询问,每次问如果一个人带着 块钱,从 结点出发到达 结点结束,在路上遇到能买的东西就买,不能买就继续往前走,等他走完这段路之后,还剩多少钱?(询问之间相互独立。)

​ 数据范围:

【分析】

​ 容易想到树剖把一个询问的问题分段。

​ 假设可以把 分成 这连续的两段,那么钱的剩余值

​ 也就是说分段之后,只要能按顺序解决每一段的问题,就能解决整个询问的问题。

​ 那么树剖就可以把一个询问分成 段,我们还可以让重链上的 序连续。

​ 对每个询问,一定都是先从 走若干逆 序的连续段,然后到达 ,再从 走若干顺 序的连续段到达

​ 于是,我们把每个询问剖出来的每个连续段分为正逆两类。

​ 然后,一起做所有询问的逆 序部分,也就是说按照逆 序扫描每个商品,遇到了一个询问的起点,就把这个询问对应的起始金钱丢入一个数据结构中,过了一个询问的中点,就把这个询问对应的剩余金钱从数据结构中取出来。然后每扫过一个 ,数据结构都要对内部 的键值进行减

​ 可以用平衡树做这个数据结构。

​ 区间减的时候分为两部分,对于 的键值,暴力取出来然后改值之后塞进去,均摊每个值最多操作 次。

​ 对于 直接打 tag 维护,因为减掉之后互不影响相对位置。

​ 逆 序部分做完之后,类似的做一遍顺 序就行了。

​ 总复杂度可以这么计算,每个询问变成了 段,但是题目性质保证我们在扫描的时候平衡树的 ,平衡树的操作还是 的,再算上每个询问有 次平衡树上的暴力修改,总复杂度大致是

​ 最后我用的 实现的,代码长度有点窒息。

​ 要注意一下 的插入,需要硬拆开再合并。

#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 100011
#define LL long long
using namespace std;
int n,m;
int tot,pre[MAXN],lin[MAXN*2],to[MAXN*2];
int fa[MAXN],son[MAXN],dep[MAXN],siz[MAXN],dfn[MAXN],anti_dfn[MAXN];
int num;
int top[MAXN];
int p[MAXN];
struct Query{
    int st,ed;
    int w,id,tree_node;
}q[MAXN];
struct WALK{
    bool is_st;
    int loc;
    int belong;
    WALK(){}
    WALK(int _is_st,int _loc,int _belong):is_st(_is_st),loc(_loc),belong(_belong){}
};
bool cmp(WALK x,WALK y)
{
    return x.loc==y.loc?x.is_st > y.is_st : x.loc < y.loc;
}
bool rev_cmp(WALK x,WALK y)
{
    return x.loc==y.loc?x.is_st > y.is_st : x.loc > y.loc;
}
vector<WALK > vec,rev_vec;

void add(int x,int y)
{
    tot++;lin[tot]=pre[x];pre[x]=tot;to[tot]=y;
}
void dfs1(int x)
{
    siz[x]=1;
    for(int i=pre[x];i;i=lin[i])
    {
        int v=to[i];
        if(v==fa[x])continue;
        fa[v]=x;
        dep[v]=dep[x]+1;
        dfs1(v);
        siz[x]+=siz[v];
        if(siz[son[x]]<siz[v])
            son[x]=v;
    }
}
void dfs2(int x)
{
    dfn[x]=++num;
    anti_dfn[num]=x;
    if(x==son[fa[x]])
        top[x]=top[fa[x]];
    else
        top[x]=x;
    if(son[x])
        dfs2(son[x]);
    for(int i=pre[x];i;i=lin[i])
    {
        int v=to[i];
        if(v==fa[x]||v==son[x])continue;
        dfs2(v);
    }
}
void LCA(int x,int y,int belong)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]] > dep[top[y]])
        {
            rev_vec.push_back(WALK(true,dfn[x],belong));
            rev_vec.push_back(WALK(false,dfn[top[x]],belong));
            x=fa[top[x]];
        }
        else
        {
            vec.push_back(WALK(true,dfn[top[y]],belong));
            vec.push_back(WALK(false,dfn[y],belong));
            y=fa[top[y]];
        }
    }
    if(dep[x] > dep[y])
    {
        rev_vec.push_back(WALK(true,dfn[x],belong));
        rev_vec.push_back(WALK(false,dfn[y],belong));
    }
    else
    {
        vec.push_back(WALK(true,dfn[x],belong));
        vec.push_back(WALK(false,dfn[y],belong));
    }   
}
struct QUEUE{
    int q[MAXN],head,tail;
    QUEUE(){head=tail=0;}
    bool empty(){return tail==head;}
    void pop(){head++;if(head==MAXN)head=0;}
    void push(int x){q[tail++]=x;if(tail==MAXN)tail=0;}
    int front(){return q[head];}
    void clear(){head=tail=0;}
};
struct FHQ_Treap{
    static const int Null = 0;
    QUEUE que;
    int num,root;
    struct node{
        int l,r,fa;
        int rnd,val,belong,siz,tag;
        node(){siz=tag=0;}
    }tr[MAXN*2];

    void init(){num=0;root=Null;que.clear();}
    void pushup(int x)
    {
        tr[x].siz=tr[tr[x].l].siz+tr[tr[x].r].siz+1;
        tr[tr[x].l].fa=tr[tr[x].r].fa=x;
    }
    void pushdown(int x)
    {
        if(tr[x].tag)
        {
            int L=tr[x].l,R=tr[x].r;
            if(L)
            {
                tr[L].val+=tr[x].tag;
                tr[L].tag+=tr[x].tag;
            }
            if(R)
            {
                tr[R].val+=tr[x].tag;
                tr[R].tag+=tr[x].tag;
            }
            tr[x].tag=0;
        }
    }
    inline int rnd(){return rand();}
    int add(int val,int belong)
    {
        int now;
        if(!que.empty())
        {
            now=que.front();
            que.pop();
        }
        else
            now = ++num;
        q[belong].tree_node=now;
        tr[now].l=tr[now].r=Null;
        tr[now].rnd=rnd();
        tr[now].siz=1;tr[now].val=val;tr[now].belong=belong;
        return now;
    }
    void split_val(int x,int k,int &l,int &r)
    {
        if(!x){l=r=Null;return;}
        pushdown(x);
        if(tr[x].val<=k){l=x;split_val(tr[x].r,k,tr[x].r,r);}
        else {r=x;split_val(tr[x].l,k,l,tr[x].l);}
        pushup(x);
    }
    void split_rank(int x,int k,int &l,int &r)
    {
        if(!x){l=r=Null;return;}
        pushdown(x);
        if(tr[tr[x].l].siz+1<=k)
        {l=x;split_rank(tr[x].r,k-tr[tr[x].l].siz-1,tr[x].r,r);}
        else
        {r=x;split_rank(tr[x].l,k,l,tr[x].l);}
        pushup(x);
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x|y;
        if(tr[x].rnd < tr[y].rnd)
        {
            pushdown(x);
            tr[x].r=merge(tr[x].r,y);pushup(x);return x;
        }
        else
        {
            pushdown(y);
            tr[y].l=merge(x,tr[y].l);pushup(y);return y;
        }
    }

    void insert(int val,int belong)
    {
        int l,r;
        split_val(root,val,l,r);
        root = merge(l,merge(add(val,belong),r));
    }

    int find_node_rank(int x)
    {
        int ans = tr[tr[x].l].siz+1;
        while(x!=root)
        {
            int fa=tr[x].fa;
            if(x==tr[fa].r)ans+=tr[tr[fa].l].siz+1;
            x=fa;
        }
        return ans;
    }

    int Delete_node(int x)
    {
        int rk=find_node_rank(x);
        int l,r,mid;
        split_rank(root,rk-1,l,r);
        split_rank(r,1,mid,r);
        que.push(mid);
        root=merge(l,r);
        return mid;
    }

    void dfs_mid(int x,int val,int &l)
    {
        pushdown(x);
        if(tr[x].l)dfs_mid(tr[x].l,val,l);
        if(tr[x].r)dfs_mid(tr[x].r,val,l);
        tr[x].l=tr[x].r=Null;
        tr[x].siz=1;tr[x].val-=val;//tag?
        int L,R;
        split_val(l,tr[x].val,L,R);
        l=merge(L,merge(x,R));
    }

    void modify(int val)
    {
        int l,mid,r;
        split_val(root,val-1,l,r);
        split_val(r,val+val-1,mid,r);
        if(r)
        {
            tr[r].val-=val;
            tr[r].tag-=val;
        }
        if(mid)dfs_mid(mid,val,l);
        root=merge(l,r);
    }

}treap;
void init()
{
    vec.clear();rev_vec.clear();
    for(int i=1;i<=n;i++)
    {
        pre[i]=0;
        son[i]=fa[i]=0;
    }
    tot=0;
    num=0;
    treap.init();
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&p[i]);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);
            add(y,x);
        }
        dfs1(1);dfs2(1);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&q[i].st,&q[i].ed,&q[i].w);
            LCA(q[i].st,q[i].ed,i);
        }
        sort(vec.begin(),vec.end(),cmp);
        sort(rev_vec.begin(),rev_vec.end(),rev_cmp);
        for(int i=n,j=0;i>=1;i--)
        {
            while(j<rev_vec.size() && rev_vec[j].loc == i && rev_vec[j].is_st)
            {
                treap.insert(q[rev_vec[j].belong].w,rev_vec[j].belong);
                j++;
            }
            treap.modify(p[anti_dfn[i]]);
            while(j<rev_vec.size() && rev_vec[j].loc == i && !rev_vec[j].is_st)
            {
                int nd=treap.Delete_node(q[rev_vec[j].belong].tree_node);
                q[treap.tr[nd].belong].w = treap.tr[nd].val;
                j++;
            }
        }

        for(int i=1,j=0;i<=n;i++)
        {
            while(j<vec.size() && vec[j].loc == i && vec[j].is_st)
            {
                treap.insert(q[vec[j].belong].w,vec[j].belong);
                j++;
            }
            treap.modify(p[anti_dfn[i]]);
            while(j<vec.size() && vec[j].loc == i && !vec[j].is_st)
            {
                int nd=treap.Delete_node(q[vec[j].belong].tree_node);
                q[vec[j].belong].w = treap.tr[nd].val;
                j++;
            }
        }

        for(int i=1;i<=m;i++)
        {
            printf("%d\n",q[i].w);
        }
    }
    return 0;
}