ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P3178 - 树上操作

2021-09-17 16:36:08  阅读:103  来源: 互联网

标签:P3178 val int LL tree mid 操作 树上 id


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

操作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 
}

 

标签:P3178,val,int,LL,tree,mid,操作,树上,id
来源: https://www.cnblogs.com/lemonGJacky/p/15305230.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有