zoukankan      html  css  js  c++  java
  • 树链剖分模板

    题目链接:https://www.luogu.com.cn/problem/P3178

    题目描述

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:

    • 操作 1 :把某个节点 x 的点权增加 a 。
    • 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    • 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    输入格式

    第一行包含两个整数 N, M 。表示点数和操作数。
    接下来一行 N 个整数,表示树中节点的初始权值。
    接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。
    再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

    输出格式

    对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

    输入输出样例

    输入 #1
    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3
    输出 #1
    6
    9
    13

    说明/提示

    对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+9;
    const double ep=1e-6;
    const int mod=998244353;
    const int MAX=1e9;
    #define mk make_pair
    #define PII pair<int,int>
    #define PLL pair<ll,ll>
    #define pb push_back
    typedef long long ll;
    ll n,m,b[maxn],size[maxn],d[maxn];
    ll f[maxn][20];
    vector<int>vec[maxn];
    ll be[maxn];
    ll pp[maxn],cnt;
    struct node{
        ll l,r,sum,lazy;
    }a[maxn<<2];
    void dfs(int x,int p)
    {
        size[x]=1;
        for(int j:vec[x])
        {
            if(j==p)continue;
            f[j][0]=x;
            d[j]=d[x]+1;
            dfs(j,x);
            size[x]+=size[j];
        }
    }
    void dfs1(int x,int chain,int p)
    {
        be[x]=chain;
        pp[x]=++cnt;
        int pos=0;
        for(int j:vec[x])
        {
            if(j==p)continue;
            if(size[j]>size[pos])pos=j;
        }
        if(!pos)return;
        dfs1(pos,chain,x);
        for(int j:vec[x])
        {
            if(j==p||j==pos)continue;
            dfs1(j,j,x);
        }
    }
    
    int lca(int a,int b)
    {
        if(d[a]<d[b])swap(a,b);
        for(int i=17;i>=0;i--)if((d[a]-d[b])>>i)a=f[a][i];
        if(a==b)return a;
        for(int i=17;i>=0;i--)if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
        return f[a][0];
    }
    void build(int k,int l,int r)
    {
        a[k].l=l,a[k].r=r;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
    }
    void pushup(int k)
    {
        a[k].sum=a[k<<1].sum+a[k<<1|1].sum;
    }
    void pushdown(int k)
    {
        if(a[k].l==a[k].r)
        {
            a[k].lazy=0;return;
        }
        a[k<<1].sum+=(a[k<<1].r-a[k<<1].l+1)*a[k].lazy;
        a[k<<1|1].sum+=(a[k<<1|1].r-a[k<<1|1].l+1)*a[k].lazy;
        a[k<<1].lazy+=a[k].lazy;
        a[k<<1|1].lazy+=a[k].lazy;
        a[k].lazy=0; 
    }
    void change(int k,int l,int r,int x)
    {
        if(a[k].l>=l&&a[k].r<=r)
        {
            a[k].sum+=(a[k].r-a[k].l+1)*x;
            a[k].lazy+=x;
            return;
        }
        if(a[k].lazy)pushdown(k);
        int mid=(a[k].l+a[k].r)>>1;
        if(l<=mid)change(k<<1,l,r,x);
        if(r>mid)change(k<<1|1,l,r,x);
        pushup(k);
    }
    ll query_SUM(int k,int l,int r)
    {
        if(a[k].lazy)pushdown(k);
        if(a[k].l>=l&&a[k].r<=r)
        {
            return a[k].sum;
        }
        int mid=(a[k].l+a[k].r)>>1;
        if(r<=mid)return query_SUM(k<<1,l,r);
        else if(l>mid)return query_SUM(k<<1|1,l,r);
        else return query_SUM(k<<1,l,mid)+query_SUM(k<<1|1,mid+1,r);
    }
    ll query(int x)
    {
        ll sum1=0;
        while(be[x]!=1)
        {
            sum1+=query_SUM(1,pp[be[x]],pp[x]);
            x=f[be[x]][0];
        }
        sum1+=query_SUM(1,1,pp[x]);
        return sum1;
    }
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
        for(int i=1;i<n;i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            vec[u].pb(v);
            vec[v].pb(u);
        }
        dfs(1,0);
        for(int i=1;i<=17;i++)for(int j=1;j<=n;j++)f[j][i]=f[f[j][i-1]][i-1];
        dfs1(1,1,-1);
        build(1,1,n);
        for(int i=1;i<=n;i++)change(1,pp[i],pp[i],b[i]);
        
        while(m--)
        {
            int op,x,y;
            scanf("%d%d",&op,&x);
            if(op==1)
            {
                scanf("%d",&y);
                change(1,pp[x],pp[x],y);
            }
            if(op==2)
            {
                scanf("%d",&y);
                change(1,pp[x],pp[x]+size[x]-1,y);
            }
            if(op==3)
            {
                printf("%lld
    ",query(x));
            }
        }
    }
    欢迎加我qq1165750856一起玩呀~
  • 相关阅读:
    终端字符颜色、样式控制
    popen——php多进程利器
    游戏技能效果与buff设定
    Linux 记录服务器负载、内存、cpu状态的PHP脚本
    简单的,省份和城市选择,非ajax版
    一道js题目
    左右结构,右边上固定、下iframe,iframe自动改变大小
    mysql 忘记root密码
    socket 学习(转载)
    子页面关闭后,更新父页面
  • 原文地址:https://www.cnblogs.com/HHHEN/p/13390452.html
Copyright © 2011-2022 走看看