树链剖分

咕咕咕

 

一、功能

  • 将树从x到y结点最短路径上所有节点的值都加上z
  • 求树从x到y结点最短路径上所有节点的值之和
  • 将以x为根节点的子树内所有节点值都加上z
  • 求以x为根节点的子树内所有节点值之和

二、概念

  • 重儿子:对于每一个非叶子节点,它的儿子中 以那个儿子为根的子树节点数最大的儿子 为该节点的重儿子
  • 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子
  • 叶子节点没有重儿子也没有轻儿子
  • 重边:一个父亲连接他的重儿子的边称为重边
  • 轻边:剩下的即为轻边
  • 重链:相邻重边连起来的 连接一条重儿子 的链叫重链

对于叶子节点,若其为轻儿子,则有一条以自己为起点的长度为1的链。每一条重链以轻儿子为起点

 

三、预处理

dfs1

要处理几件事情:

  • 标记每个点的深度dep[]
  • 标记每个点的父亲fa[]
  • 标记每个非叶子节点的子树大小(含它自己)
  • 标记每个非叶子节点的重儿子编号son[]

dfs2

要预处理几件事情:

  • 标记每个点的新编号
  • 赋值每个点的初始值到新编号上
  • 处理每个点所在链的顶端
  • 处理每条链

顺序:先处理重儿子再处理轻儿子

 

四、树链剖分

用线段树来写

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

inline int read()
{
    int sum = 0,p = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
            p = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (sum *= 10) += ch - '0';
        ch = getchar();
    }
    return sum * p;
}

#define mid ((l + r) >> 1)
#define len (r - l + 1)
#define lson o << 1,l,mid
#define rson o << 1 | 1,mid + 1,r

const int maxn = 2e5 + 5,maxm = 1e5 + 5;
int n,m,r,p;
int val[maxn],dep[maxn],fa[maxn],siz[maxn],son[maxn],id[maxn],nval[maxn],top[maxn];
//val点权 ,dep点深度 ,fa父节点编号,siz子树大小,son重儿子,id新编号,nval新编号下的点权数,top当前链顶端结点 
int res,tot,lazy[maxn * 4],a[maxn * 4];
int cnt,head[maxn]; 
struct edge
{
    int nxt,to;
}e[maxm * 4];

void add(int a,int b)
{
    e[++cnt].nxt = head[a];
    e[cnt].to = b;
    head[a] = cnt;
}

void dfs1(int o,int f,int deep)//o当前结点,f父节点,deep深度 
{
    dep[o] = deep;
    fa[o] = f; 
    siz[o] = 1; 
    int maxson = -1;
    for(int i = head[o];i;i = e[i].nxt)
    {
        int v = e[i].to;
        if(v == f)
            continue;
        dfs1(v,o,deep+1);
        siz[o] += siz[v];
        if(siz[v] > maxson)
        {
            son[o] = v;
            maxson = siz[v];
        }
    } 
}

void dfs2(int o,int topf)
{
    id[o] = ++tot;
    nval[tot] = val[o];
    top[o] = topf;
    if(!son[o])
        return;
    dfs2(son[o],topf);
    for(int i = head[o];i;i = e[i].nxt)
    {
        int v = e[i].to;
        if(v == fa[o] || v == son[o])
            continue;
        dfs2(v,v);
    } 
}

//---------------线段树---------------- 

void pushdown(int o,int lenn)
{
    lazy[o << 1] += lazy[o];
    lazy[o << 1 | 1] += lazy[o];
    a[o << 1] += lazy[o] * (lenn - (lenn >> 1));
    a[o << 1 | 1] += lazy[o] * (lenn >> 1);
    a[o << 1] %= p;
    a[o << 1 | 1] %= p;
    lazy[o] = 0;
}

void build(int o,int l,int r)
{
    if(l == r)
    {
        a[o] = nval[l] % p;
        return;
    }
    build(lson);
    build(rson);
    a[o] = (a[o << 1] + a[o << 1 | 1])% p;
}

void update(int o,int l,int r,int ql,int qr,int k)
{
    if(ql <= l && r <= qr)
    {
        lazy[o] += k;
        a[o] += k * len;
        return;
    }
    if(lazy[o])
        pushdown(o,len);
    if(ql <= mid)
        update(lson,ql,qr,k);
    if(qr > mid)
        update(rson,ql,qr,k);
    a[o] = (a[o << 1] + a[o << 1 | 1])%p;
}

void query(int o,int l,int r,int ql,int qr)
{
    if(ql <= l && r <= qr)
    {
        res = (res +a[o])%p;
        return;
    }
    if(lazy[o])
        pushdown(o,len);
    if(ql <= mid)
        query(lson,ql,qr);
    if(qr > mid)
        query(rson,ql,qr);
}

//---------------线段树—————————————— 

void updr(int l,int r,int k)
{
    k %= p;
    while(top[l] != top[r])
    {
        if(dep[top[l]] < dep[top[r]])
            swap(l,r);
        update(1,1,n,id[top[l]],id[l],k);
        l = fa[top[l]];
    }
    if(dep[l] > dep[r])
        swap(l,r);
    update(1,1,n,id[l],id[r],k);
}

int queryr(int l,int r)
{
    int ans = 0;
    while(top[l] != top[r])
    {
        if(dep[top[l]] < dep[top[r]])
            swap(l,r);
        res = 0;
        query(1,1,n,id[top[l]],id[l]);
        ans = (ans + res)%p;
        l = fa[top[l]];
    }
    if(dep[l] > dep[r])
        swap(l,r);
    res = 0;
    query(1,1,n,id[l],id[r]);
    return (ans + res) % p;
}

void updson(int o,int k)
{
    update(1,1,n,id[o],id[o] + siz[o] - 1,k);
}

int qson(int o)
{
    res = 0;
    query(1,1,n,id[o],id[o] + siz[o] - 1);
    return res;
}

int main()
{
    n = read(),m = read(),r = read(),p = read();
    for(int i = 1;i <= n;i++)
        val[i] = read();
    for(int i = 1;i < n;i++)
    {
        int a = read(),b = read();
        add(a,b);
        add(b,a);
    }
    dfs1(r,0,1);
    dfs2(r,r);
    build(1,1,n); 
    while(m--)
    {
        int opt = read();
        if(opt == 1)
        {
            int x = read(),y = read(),z = read();
            updr(x,y,z);
        }
        else if(opt == 2)
        {
            int x = read(),y = read();
            printf("%d\n",queryr(x,y));
        }
        else if(opt == 3)
        {
            int x = read(),y = read();
            updson(x,y);
        }
        else
        {
            int x = read();
            printf("%d\n",qson(x));
        }
    }
    return 0;
}

 

 

 

 

 

 

posted @ 2019-07-23 15:09  darrrr  阅读(254)  评论(0编辑  收藏  举报