zoukankan      html  css  js  c++  java
  • 【bzoj4034】【HAOI2015】树上操作

    题目描述

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
    操作,分为三种:
    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。


    输入

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


    输出

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


    样例输入

    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


    样例输出

    6
    9
    13

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



    题解

    树剖裸题。

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    
    const int maxn=1e5+5;
    const int maxm=2e5+5;
    
    ll fir[maxn],to[maxm],nex[maxm],ecnt;
    ll n,m,r,p,w[maxn],cnt,op,x,y,z;
    ll wt[maxn],son[maxn],top[maxn],fa[maxn],sz[maxn],dep[maxn],id[maxn];
    
    struct SegmentTree{
        ll l,r,v,add;
    }st[maxn*4];
    
    void add_edge(int u,int v){
        nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;
    }
    
    void dfs1(int x,int f,int deep){
        dep[x]=deep;
        fa[x]=f;
        sz[x]=1;
        int maxson=-1;
        for(int e=fir[x];e;e=nex[e]){
            int v=to[e];
            if(v==f) continue;
            dfs1(v,x,deep+1);
            sz[x]+=sz[v];
            if(sz[v]>maxson) maxson=sz[v],son[x]=v;
        }
    }
    
    void dfs2(int x,int topf){
        top[x]=topf;
        id[x]=++cnt;
        wt[cnt]=w[x];
        if(!son[x]) return ;
        dfs2(son[x],topf);
        for(int e=fir[x];e;e=nex[e]){
            int v=to[e];
            if(v==fa[x]||v==son[x]) continue;
            dfs2(v,v);
        }
    }
    
    void pushup(int root){
        st[root].v=(st[root*2].v+st[root*2+1].v);
    }
    
    void build(int root,int l,int r){
        st[root].l=l;st[root].r=r;
        if(l==r) st[root].v=wt[l];
        else{
            int m=l+r>>1;
            build(root*2,l,m);
            build(root*2+1,m+1,r);
            pushup(root);
        }
    }
    
    void pushdown(int root){
        st[root*2].v=(st[root*2].v+st[root].add*(st[root*2].r-st[root*2].l+1));
        st[root*2+1].v=(st[root*2+1].v+st[root].add*(st[root*2+1].r-st[root*2+1].l+1));
        st[root*2].add=(st[root*2].add+st[root].add);
        st[root*2+1].add=(st[root*2+1].add+st[root].add);
        st[root].add=0;
    }
    
    void add(int root,int l,int r,int val){
        if(st[root].l>r||st[root].r<l) return ;
        if(st[root].l>=l&&st[root].r<=r){
            st[root].v=(st[root].v+val*(st[root].r-st[root].l+1));
            st[root].add=(st[root].add+val);
        }
        else{
            pushdown(root);
            add(root*2,l,r,val);
            add(root*2+1,l,r,val);
            pushup(root);
        }
    }
    
    ll query(int root,int l,int r){
        if(st[root].l>r||st[root].r<l) return 0;
        if(st[root].l>=l&&st[root].r<=r) return st[root].v;
        pushdown(root);
        return (query(root*2,l,r)+query(root*2+1,l,r));
    }
    
    void Change(int x,int y,int val){
        int f1=top[x],f2=top[y];
        while(f1!=f2){
            if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
            add(1,id[f1],id[x],val);
            x=fa[f1];f1=top[x];
        }
        if(dep[x]>dep[y]) swap(x,y);
        add(1,id[x],id[y],val);
    }
    
    ll Query(int x,int y){
        ll f1=top[x],f2=top[y],ans=0;
        while(f1!=f2){
            if(dep[f1]<dep[f2]) swap(f1,f2),swap(x,y);
            ans=(ans+query(1,id[f1],id[x]));
            x=fa[f1];f1=top[x];
        }
        if(dep[x]>dep[y]) swap(x,y);
        ans=(ans+query(1,id[x],id[y]));
        return ans;
    }
    
    void Change_tree(int x,int val){
        add(1,id[x],id[x]+sz[x]-1,val);
    }
    
    int Query_tree(int x){
        return query(1,id[x],id[x]+sz[x]-1);
    }
    
    template<typename T>void read(T& aa){
        char cc; ll ff;aa=0;cc=getchar();ff=1;
        while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
        if(cc=='-') ff=-1,cc=getchar();
        while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
        aa*=ff;
    }
    
    int main(){
        read(n),read(m);
        for(int i=1;i<=n;i++) read(w[i]);
        for(int i=1;i<n;i++){
            read(x),read(y);
            add_edge(x,y);
            add_edge(y,x);
        }
        dfs1(1,0,1);
        dfs2(1,1);
        build(1,1,n);
        while(m--){
            read(op);
            if(op==1){
                read(x);read(y);
                Change(x,x,y);
            }
            else if(op==2){
                read(x),read(y);
                Change_tree(x,y);
            }
            else if(op==3){
                read(x);
                cout<<Query(x,1)<<endl;
            }
        }
        return 0;
    }
  • 相关阅读:
    .NET Web应用配置本地IIS(实现Visual Studio离线运行与调试)
    Windows10 IIS Web服务器安装配置
    Visual Studio 2022 Preview设置简体中文
    nlp中各中文预训练模型的输入和输出
    numpy和Pytorch对应的数据类型
    Zookeeper入门看这篇就够了
    做一个有温度的程序员
    Apollo 配置中心详细教程
    浅析 DDD 领域驱动设计
    把之前CompletableFuture留下的坑给填上。
  • 原文地址:https://www.cnblogs.com/rlddd/p/9557980.html
Copyright © 2011-2022 走看看