题解 P5314 【[Ynoi2011]ODT】

原文链接

一道卡常好题。

我们考虑暴力做法,我们就可以直接对每个点维护相邻的点的平衡树,修改就暴力修改,查询就直接查询就可以了。

显然不对

那么我们怎么优化这个算法呢?

我们可以先进行树链剖分,然后每个点只维护她的轻儿子的平衡树。

为什么要怎么做呢?它与暴力有什么区别呢?

考虑树剖的性质。我们每次修改时,最多经过\(logn\)条重链,每条链只有链头的父亲的一个轻儿子(即链头)发生了改变。我们暴力删除插入,复杂度是\(log^2n\)的。

我们每次询问,就暴力把那个点,她的父亲,她的重儿子插入在查询第\(k\)小就可以了。

然后,你告诉我你只有80分?

好吧,实话实说,这题卡平衡树。如果你用\(Splay\)\(FHQ\;Treap\)是卡不过去的,不信你试试?试试就逝世,我们要用常数更优秀的平衡树。我这里选择了\(WBLT\)。然而你还是只有\(80\)分?,快读加火车头多交几遍暴力*过去\(ok\)了。

另外有两个小细节

  1. 一定要看这个点到底有没有重儿子与父亲。

  2. 你在修改跳链,最后跳到一个链上时,一定要看一下是不是跳到了链头,如果是还要做一次额外修改。

最后,\(WBLT\)大法吼啊!\(orz\;lxl\)

\(Code\)

struct Node
{
    int val,siz;
    Node *lc,*rc;
    Node(int siz,int val,Node *lc,Node *rc) : siz(siz),val(val),lc(lc),rc(rc) {}
    Node() {}
};

struct edge
{
    int v,nxt;
}e[maxn<<1];
int head[maxn],kt,n,id[maxn];
int dfn[maxn],dep[maxn],son[maxn],siz[maxn],top[maxn],fa[maxn],cnt,a[maxn];

inline int max(const int &x,const int &y) {return x>y?x:y;}
inline int min(const int &x,const int &y) {return x<y?x:y;}
inline void add(const int &u,const int &v) {e[++kt]=(edge){v,head[u]};head[u]=kt;}

struct Leafy_Tree
{
    Node *rt[maxn],*stk[maxn<<2],utk[maxn<<2],*null;
    int utot;
    const int ratio=3;
    #define newnode(a,b,c,d) (&(*stk[utot++]=Node(a,b,c,d)))
    #define merge(a,b) newnode(a->siz+b->siz,b->val,a,b)
    inline void init(int n)
    {
        null=new Node(0,0,0,0);
        for(int i=0;i<n*3;++i)
            stk[i]=&utk[i];
        for(int i=0;i<=n+1;++i)
            rt[i]=newnode(1,2147483647,null,null);
    }
    inline void rotate(Node *u)
    {
        if(u->lc->siz > u->rc->siz*ratio)
            u->rc=merge(u->lc->rc,u->rc),stk[--utot]=u->lc,u->lc=u->lc->lc;
        else if(u->rc->siz > u->lc->siz*ratio)
            u->lc=merge(u->lc,u->rc->lc),stk[--utot]=u->rc,u->rc=u->rc->rc;
    }
    inline void pushup(Node *u)
    {
        if(!u->lc->siz) return;
        u->siz=u->lc->siz+u->rc->siz;
        u->val=u->rc->val;
    }
    inline void insert(Node *u,int val)
    {
        if(u->siz==1)
        {
            u->lc=newnode(1,min(val,u->val),null,null);
            u->rc=newnode(1,max(val,u->val),null,null);
        }
        else insert(val > u->lc->val ? u->rc : u->lc,val);
        pushup(u);rotate(u);
    }
    inline void erase(Node *u,int val)
    {
        if(u->lc->siz==1&&u->lc->val==val)
            stk[--utot]=u->lc,stk[--utot]=u->rc,*u=*u->rc;
        else if(u->rc->siz==1&&u->rc->val==val)
            stk[--utot]=u->lc,stk[--utot]=u->rc,*u=*u->lc;
        else erase(val > u->lc->val ? u->rc : u->lc,val);
        pushup(u);rotate(u);
    }
    inline int kth(Node *u,int k)
    {
        if(u->siz==1) return u->val;
        return k > u->lc->siz ? kth(u->rc,k-u->lc->siz) : kth(u->lc,k);
    }
}leafy;

struct BIT
{
    int sum[maxn];
    #define lowbit(x) (x&(-x))
    inline void modify(int x,int val) {while(x<=n+5) sum[x]+=val,x+=lowbit(x);}
    inline int query(int x) {int res=0;while(x) res+=sum[x],x-=lowbit(x);return res;}
}bit;

void dfs1(int u,int f)
{
    fa[u]=f;dep[u]=dep[f]+1;siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt)
    if(e[i].v!=f)
    {
        dfs1(e[i].v,u);siz[u]+=siz[e[i].v];
        if(siz[e[i].v]>siz[son[u]]) son[u]=e[i].v;
    }
}

void dfs2(int u,int topf)
{
    top[u]=topf;dfn[u]=++cnt;id[cnt]=u;
    if(!son[u]) return;
    dfs2(son[u],topf);
    for(int i=head[u];i;i=e[i].nxt)
        if(e[i].v!=fa[u]&&e[i].v!=son[u])
            dfs2(e[i].v,e[i].v),leafy.insert(leafy.rt[u],a[e[i].v]);
}

inline void modify(int u,int v,int val)
{
    while(top[u]^top[v])
    {
        if(dep[top[u]]<dep[top[v]]) u^=v^=u^=v;
        if(fa[top[u]]) leafy.erase(leafy.rt[fa[top[u]]],bit.query(dfn[top[u]]));
        bit.modify(dfn[top[u]],val),bit.modify(dfn[u]+1,-val);
        if(fa[top[u]]) leafy.insert(leafy.rt[fa[top[u]]],bit.query(dfn[top[u]]));
        u=fa[top[u]];
    }
    if(dep[u]>dep[v]) u^=v^=u^=v;
    if(u==top[u]&&fa[u]) leafy.erase(leafy.rt[fa[u]],bit.query(dfn[u]));
    bit.modify(dfn[u],val);bit.modify(dfn[v]+1,-val);
    if(u==top[u]&&fa[u]) leafy.insert(leafy.rt[fa[u]],bit.query(dfn[u]));
}

inline int query(int u,int k)
{
    int valu=bit.query(dfn[u]),valf,vals,ans;
    leafy.insert(leafy.rt[u],valu);
    if(fa[u]) valf=bit.query(dfn[fa[u]]),leafy.insert(leafy.rt[u],valf);
    if(son[u]) vals=bit.query(dfn[son[u]]),leafy.insert(leafy.rt[u],vals);
    ans=leafy.kth(leafy.rt[u],k);
    leafy.erase(leafy.rt[u],valu);
    if(fa[u]) leafy.erase(leafy.rt[u],valf);
    if(son[u]) leafy.erase(leafy.rt[u],vals);
    return ans;
}

int main()
{
    int opt,x,y,z,t;
    read(n);read(t);
    for(int i=1;i<=n;++i)
        read(a[i]);
    for(int i=1;i<n;++i)
    {
        read(x);read(y);
        add(x,y);add(y,x);
    }
    leafy.init(n);
    dfs1(1,0);dfs2(1,1);
    for(int i=1;i<=n;++i)
        bit.modify(i,a[id[i]]),bit.modify(i+1,-a[id[i]]);
    while(t--)
    {
        read(opt);read(x);read(y);
        if(opt==1) read(z),modify(x,y,z);
        else write(query(x,y),'\n');
    }
    flush();
    return 0;
}
posted @ 2020-09-02 21:48  试试事实上吗  阅读(232)  评论(0编辑  收藏  举报
Live2D