题意

三种操作:

①区间增值

②某一个点换父亲

③求子树和

\(1\leq n\leq 100000\)

分析

Splay维护dfn序。

小结

(1)使用Splay,通常要在Splay的两端各添加一个虚拟节点,防止没有前驱和后继的情况。

(2)使用Splay的时候,要注意我们的key值是什么,与附加值进行区分。

(3)在父亲连接儿子的时候,如果我们也存父亲的情况,那么要记得儿子连向父亲。

(4)Splay是一种很难调试的数据结构,所以要掌握一种技巧:静态调试。

void Traver(int x) {
    if (!x) return;
    Traver(tr[x].c[0]);
    printf("%d ",x);
    Traver(tr[x].c[1]);
}

(5)这类知道对应点位置,不知道其在树上位置的题,通常用Splay来解决。因为Treap要进行合并和分裂,需要知道在树上的位置。当然有一些处理方法:①记录父亲 ②相同权值不同化,记一个pair

(6)只有换根:分类讨论

定向link-cut:Splay维护dfn序

(7)把树变成链的三种序列:①每个出现一次 ②每个出现两次 ③每个出现度数次

代码

#pragma comment(linker, "/STACK:102400000,102400000")

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;

#define rep(i,a,b) for (int i=(a);i<=(b);i++)
#define per(i,a,b) for (int i=(a);i>=(b);i--)

#define lc tr[x].c[0]
#define rc tr[x].c[1]

#define pb push_back

typedef long long LL;

const int N=131072;
const int S=262144;

int n,m;
int w[N];
vector<int> g[N];

int tot;
int s[N],e[N];

struct Tree {
    int c[2]; int fa;
    int sz;
    LL val,sum,tag;
    Tree(int _lc=0,int _rc=0,int _fa=0,LL _val=0) {
        c[0]=_lc,c[1]=_rc,fa=_fa;
        sz=1;
        val=_val; sum=_val; tag=0;
    }
}tr[S];
int st[S],len;

LL rd(void) {
    LL x=0,f=1; char c=getchar();
    while (!isdigit(c)) {
        if (c=='-') f=-1;
        c=getchar();
    }
    while (isdigit(c)) {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}

void DFS(int x,int fa) {
    tot++; st[tot]=x; s[x]=tot;
    rep(i,1,g[x].size()) {
        int nx=g[x][i-1];
        if (nx!=fa)
            DFS(nx,x);
    }
    tot++; st[tot]=x; e[x]=tot;
}

void Pushup(int x) {
    tr[x].sz=tr[lc].sz+tr[rc].sz+1;
    tr[x].sum=tr[lc].sum+tr[rc].sum+tr[x].val;
}

void Clear(int x) {
    if (tr[x].tag!=0) {
        if (lc>0) {
            tr[lc].val+=tr[x].tag;
            tr[lc].tag+=tr[x].tag;
            tr[lc].sum+=tr[x].tag*tr[lc].sz;
        }
        if (rc>0) {
            tr[rc].val+=tr[x].tag;
            tr[rc].tag+=tr[x].tag;
            tr[rc].sum+=tr[x].tag*tr[rc].sz;
        }
        tr[x].tag=0;
    }
}

void Rotate(int x) {
    int y=tr[x].fa,z=tr[y].fa;
    int l=!(tr[y].c[0]==x),r=l^1;
    if (z>0) {
        if (tr[z].c[0]==y)
            tr[z].c[0]=x;
        else tr[z].c[1]=x;
    }
    tr[x].fa=z; tr[y].fa=x;
    if (tr[x].c[r]>0) tr[tr[x].c[r]].fa=y;
    tr[y].c[l]=tr[x].c[r]; Pushup(y);
    tr[x].c[r]=y; Pushup(x);
}

void Tsunami(int x) {
    len=0; st[++len]=x;
    for (int i=x;tr[i].fa>0;i=tr[i].fa)
        st[++len]=tr[i].fa;
    per(i,len,1) Clear(st[i]);
}

void Splay(int x,int rt=0) {
    Tsunami(x);
    while (tr[x].fa!=rt) {
        int y=tr[x].fa,z=tr[y].fa;
        if (z!=rt) {
            if ((tr[y].c[0]==x)^(tr[z].c[0]==y))
                Rotate(x);
            else Rotate(y);
        }
        Rotate(x);
    }
}

int Pre(int x) {
    Splay(x);
    x=lc; while (rc>0) x=rc;
    return x;
}

int Nxt(int x) {
    Splay(x);
    x=rc; while (lc>0) x=lc;
    return x;
}

LL Sum_Sub(int x) {
    int l=s[x],r=e[x];
    l=Pre(l),r=Nxt(r);
    Splay(l); Splay(r,l);
    return tr[tr[r].c[0]].sum;
}

void Add_Sub(int x,int y) {
    int l=s[x],r=e[x];
    l=Pre(l),r=Nxt(r);
    Splay(l); Splay(r,l);
    tr[tr[r].c[0]].val+=y;
    tr[tr[r].c[0]].tag+=y;
    tr[tr[r].c[0]].sum+=(LL)tr[tr[r].c[0]].sz*y;
    Pushup(r); Pushup(l);
}

void Link_Cut(int x,int y) {
    int l=s[x],r=e[x];
    l=Pre(l),r=Nxt(r);
    Splay(l); Splay(r,l);
    int t=tr[r].c[0]; tr[r].c[0]=0; Pushup(r); Pushup(l);

    int sy=s[y],ny=Nxt(sy);
    Splay(sy); Splay(ny,sy);
    tr[ny].c[0]=t; tr[t].fa=ny; Pushup(ny); Pushup(sy);
}

void Traver(int x) {
    if (!x) return;
    Traver(tr[x].c[0]);
    printf("%d ",x);
    Traver(tr[x].c[1]);
}

int main(void) {
    #ifndef ONLINE_JUDGE
    freopen("sd.in","r",stdin);
    freopen("sd.out","w",stdout);
    #endif

    n=rd(),m=rd();
    rep(i,1,n) w[i]=rd();
    rep(i,1,n-1) {
        int x=rd(),y=rd();
        g[x].pb(y),g[y].pb(x);
    }

    DFS(1,-1);
    rep(i,1,n) {
        tr[s[i]]=Tree(0,s[i]+1,s[i]-1,w[i]);
        tr[e[i]]=Tree(0,e[i]+1,e[i]-1,w[i]);
    }
    tr[0].sz=0;
    tr[tot].c[1]=tot+1; tr[tot+1]=Tree(0,0,tot,0);
    tr[tot+2]=Tree(0,1,0,0); tr[1].fa=tot+2;
    per(i,tot,1) Pushup(i); Pushup(tot+2);

    rep(i,1,m) {
        int kd=rd(); int x,y; LL res;
        switch (kd) {
            case 1:
                x=rd();
                res=Sum_Sub(x)>>1;
                printf("%lld\n",res);
                break;
            case 2:
                x=rd(),y=rd();
                Add_Sub(x,y);
                break;
            case 3:
                x=rd(),y=rd();
                Link_Cut(x,y);
                break;
        }
//      Splay(1); Traver(1); printf("\n");
    }

    return 0;
}

【xsy1019】小A的树论的更多相关文章

  1. 小机房的树 codevs 2370

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description 小机房有棵焕狗种的树 ...

  2. 【codevs2370】小机房的树 LCA 倍增

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0 ...

  3. Codevs 2370 小机房的树

    2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为 ...

  4. 牛客挑战赛30 小G砍树 树形dp

    小G砍树 dfs两次, dp出每个点作为最后一个点的方案数. #include<bits/stdc++.h> #define LL long long #define fi first # ...

  5. CodeVs.2370 小机房的树 ( LCA 倍增 最近公共祖先)

    CodeVs.2370 小机房的树 ( LCA 倍增 最近公共祖先) 题意分析 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天, ...

  6. LCA(倍增在线算法) codevs 2370 小机房的树

    codevs 2370 小机房的树 时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点, ...

  7. 【BZOJ5072】[Lydsy十月月赛]小A的树 树形DP

    [BZOJ5072][Lydsy十月月赛]小A的树 题解:考虑我们从一个联通块中替换掉一个点,导致黑点数量的变化最多为1.所以我们考虑维护对于所有的x,y的最大值和最小值是多少.如果询问的y在最大值和 ...

  8. codevs——2370 小机房的树

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description 小机房有棵焕狗种的树,树上有N个 ...

  9. codevs2370 小机房的树 x

    2370 小机房的树  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond   题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号 ...

随机推荐

  1. innerHTML

    对于innerHTML 属性,几乎所有的元素都有innerHTML属性,它是一个字符串,用来设置或获取位于对象起始和结束标签内的HTML.(获取HTML当前标签的起始和结束里面的内容) 下面的例子返回 ...

  2. WIN8系统安装软件时提示"扩展属性不一致"的解决方法

    单位新添加了两台T440P笔记本电脑,需要安装五笔输入法,同事一直安装不上.开始以为是WIN8系统跟输入法不兼容的问题,怀疑是输入法下载有误.于是直接在输入法官网下载了输入法,问题依旧:扩展属性不一致 ...

  3. SQL语句中:UNION与UNION ALL的区别

    有些人看到题目,瞬间觉得楼主也太弱了吧,这种问题也要拿出来写,这种问题 随便会点sql 的人基本都会 Union   是会删除冗余数据 Union ALL 不会删除冗余数据 将所有的结果都展现给用户 ...

  4. js实现继承的五种方式

    function Parent(firstname) { this.fname=firstname; ; this.sayAge=function() { console.log(this.age); ...

  5. java开发_读写txt文件操作

    package com.mi.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStr ...

  6. jqueryui引用出错(base is not a constructor,widget no found)

    出错的原因,主要是引用顺序出错. 正确顺序如下: query本身必须放在第一位: <script src="../../../Scripts/Jquery1.7.2/jquery-1. ...

  7. MVC(一)

    Webform请求模式 MVC请求模式 第一个及以下引用点击属性,拷贝到本地,在部署MVC时,将所有引用属性都改为拷贝到本地编译 建立控制器与视图 建立路由 {}标志占位符 将系统自动建立MVC项目V ...

  8. Linux C Programing - Arguments(2)

    #include <iostream> #include <stdlib.h> #include <stdio.h> //printf #include <u ...

  9. 自己封装的 recyclerView的 BaseAdapter,带item点击和长按事件。

    第一种是把创建viewholder的步骤给子类来做. 第二种是参照陈宇明的博客,试着只暴露给子类设置holder属性的方法.(还未测试条目中控件的点击事件能否成功) 代码如下: /** * Creat ...

  10. [linux系统]--Sed

    删除:d命令 $ sed ‘2d’ example—–删除example文件的第二行. $ sed ‘2,$d’ example—–删除example文件的第二行到末尾所有行. $ sed ‘$d’ ...