P3178 - 树上操作

时间:2021-09-17
本文章向大家介绍P3178 - 树上操作,主要包括P3178 - 树上操作使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

没什么特殊的一道树链剖分板子题,可以作为树剖入门题

操作1单点修改即可

操作2和操作3为树链剖分基础操作

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
#define lid (id << 1)
#define rid (id << 1) | 1
typedef long long LL;

const int maxn=1e5+10;

struct Edge{
    int nex;
    int to;
}E[2*maxn];

LL rt,n,m,r,cnt,tot;
LL mod=9223372036854775806;
LL a[2*maxn];
LL head[maxn];
LL f[maxn];//节点u的父亲节点 
LL d[maxn];//节点u的深度 
LL size[maxn];//以u为根的子树节点个数
LL son[maxn];//重儿子 
LL rk[maxn];//当前dfs标号在树中所对应的节点 
LL top[maxn];//当前节点所在链的顶端节点 
LL id[maxn];//树中每个节点剖分以后的新编号(决定DFS执行顺序) 

struct seg_tree 
{
    LL l, r;
    LL lazy;
    long long sum;
} tree[maxn << 2];

void build(LL id, LL l, LL r) 
{
    tree[id].l = l;
    tree[id].r = r;
    if (l == r)
    {
        tree[id].sum = a[rk[l]];
        return;
    }
    int mid = (l + r) >> 1;
    build(lid, l, mid);
    build(rid, mid + 1, r);
    tree[id].sum = (tree[lid].sum + tree[rid].sum)%mod;
}

void pushdown(LL id) 
{
    if (tree[id].lazy != 0 && tree[id].l != tree[id].r) 
    {
        LL val = tree[id].lazy;
        (tree[lid].lazy += val)%=mod;
        (tree[rid].lazy += val)%=mod;
        tree[lid].sum += val * (tree[lid].r - tree[lid].l + 1);
        tree[rid].sum += val * (tree[rid].r - tree[rid].l + 1);
        tree[id].lazy = 0;
    }
}


void add(LL id, LL val,LL l, LL r) 
{
    pushdown(id);
    if (tree[id].l == l && tree[id].r == r) 
    {
        tree[id].lazy += val;
        tree[id].sum += val * (r - l + 1);
        tree[id].sum%=mod;
        return;
    }
    LL mid = (tree[id].l + tree[id].r) >> 1;
    if (mid >= r)
        add(lid, val, l, r);
    else if (mid < l)
        add(rid, val, l, r);
    else
    {
        add(lid, val, l, mid);
        add(rid, val, mid + 1, r);
    }
    tree[id].sum = (tree[lid].sum + tree[rid].sum)%mod;
}

long long query(LL id,LL l, LL r) 
{
    pushdown(id);
    if (tree[id].l == l && tree[id].r == r)
        return tree[id].sum;
    LL mid = (tree[id].l + tree[id].r) >> 1;
    if (mid >= r)
        return query(lid, l, r)%mod;
    else if (mid < l)
        return query(rid, l, r)%mod;
    else return (query(lid, l, mid) + query(rid, mid + 1, r))%mod;
}

void addedge(int u,int v)
{
    E[++tot].nex=head[u];
    E[tot].to=v;
    head[u]=tot;
}

void dfs1(int u,int fa,int depth)
{
    f[u]=fa;
    d[u]=depth;
    size[u]=1;
    for(int i=head[u];i;i=E[i].nex)
    {
        int v=E[i].to;
        if(v==fa)continue;
        dfs1(v,u,depth+1);
        size[u]+=size[v];
        if(size[v]>size[son[u]])
        {
            son[u]=v;
        }//选取重儿子
    }
}

void dfs2(int u,int t)//t为重链顶端,连接重链,记录dfs,处理top,id,rk以保证dfs序连续 
{
    top[u]=t;
    id[u]=++cnt;//记录dfs序
    rk[cnt]=u;//记录相应dfs序的节点
    if(!son[u])
    {
        return;
    }
    dfs2(son[u],t);
    for(int i=head[u];i;i=E[i].nex)
    {
        int v=E[i].to;
        if(v!=son[u]&&v!=f[u])
        dfs2(v,v); //轻链底端结点即为重链的顶端 
    }
}

LL sum(int x,int y)
{
    LL ans=0;
    int fx=top[x];
    int fy=top[y];
    while(top[x]!=top[y])
    {
        if(d[top[x]]<d[top[y]])swap(x,y);
        (ans+=query(1,id[top[x]],id[x]))%=mod;
        x=f[top[x]];
    }
    if(id[x]>id[y])swap(x,y);
    (ans+=query(1,id[x],id[y]))%=mod;
    return ans;
}

void update(int x,int y,int c)
{
    while(top[x]!=top[y])
    {
        if(d[top[x]]<d[top[y]])
        {
            swap(x,y);
        }
        add(1,c,id[top[x]],id[x]);
        x=f[top[x]];
    }
    if(id[x]>id[y])swap(x,y);
    add(1,c,id[x],id[y]);
}

int main(){
    scanf("%lld%lld",&n,&m);
    r=1;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
        addedge(y,x);
    }
    dfs1(r,0,1);
    dfs2(r,r);
    rt=1;
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        LL flag,x,y,z;
        scanf("%lld",&flag);
        if(flag==1)
        {
            scanf("%lld%lld",&x,&z);
            add(1,z,id[x],id[x]);
        }
        if(flag==3){
            scanf("%lld",&x);
            printf("%lld\n",sum(x,1));
        }
        if(flag==2)
        {
            scanf("%lld%lld",&x,&y);
            add(1,y,id[x],id[x]+size[x]-1);
        }
    }
    return 0;
    //处理深度d以及父节点f 
}

原文地址:https://www.cnblogs.com/lemonGJacky/p/15305230.html