zoukankan      html  css  js  c++  java
  • BZOJ 4034 [HAOI2015]T2(树链剖分)

    【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=4034

     

    【题目大意】

      有一棵点数为 N 的树,以点 1 为根,且树点有边权。

      有 M 个 操作,分为三种:

        操作 1 :把某个节点 x 的点权增加 a 。

        操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。

        操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    【题解】

      树链剖分之后变成简单的线段树区间和维护。

    【代码】

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N=200005;
    typedef long long LL;
    int x,y,d[N],num[N],ed=0,u,w,n,m,i,v[N],vis[N],f[N],g[N];
    int nxt[N],size[N],son[N],st[N],en[N],dfn,top[N],t,a[N];
    void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
    void dfs(int x){
        size[x]=1;
        for(int i=g[x];i;i=nxt[i])if(v[i]!=f[x]){
            f[v[i]]=x,d[v[i]]=d[x]+1;
            dfs(v[i]),size[x]+=size[v[i]];
            if(size[v[i]]>size[son[x]])son[x]=v[i];
        }
    }
    void dfs2(int x,int y){
        if(x==-1)return;
        st[x]=++dfn;top[x]=y;
        if(son[x])dfs2(son[x],y);
        for(int i=g[x];i;i=nxt[i])if(v[i]!=son[x]&&v[i]!=f[x])dfs2(v[i],v[i]);
        en[x]=dfn;
    }
    struct node{LL l,r,a,b,tag,sum;}T[N*4];
    int tot=0;
    void addtag(LL x,LL tag){
        T[x].tag+=tag;
        T[x].sum+=(T[x].b-T[x].a+1)*tag;
    }
    void pb(LL x){
        if(T[x].l){addtag(T[x].l,T[x].tag);addtag(T[x].r,T[x].tag);}
        T[x].tag=0;
    }
    void up(LL x){T[x].sum=T[T[x].l].sum+T[T[x].r].sum;}
    void build(int l,int r){
        int x=++tot;
        T[x].a=l;T[x].b=r;T[x].tag=T[x].l=T[x].r=T[x].sum=0;
        if(l==r){return;}
        LL mid=(l+r)>>1;
        T[x].l=tot+1;build(l,mid);
        T[x].r=tot+1;build(mid+1,r);
        up(x);
    }
    void change(LL x,LL a,LL b,LL p){
        if(T[x].a>=a&&T[x].b<=b){addtag(x,p);return;}
        if(T[x].tag)pb(x); LL mid=(T[x].a+T[x].b)>>1;
        if(mid>=a&&T[x].l)change(T[x].l,a,b,p);
        if(mid<b&&T[x].r)change(T[x].r,a,b,p);up(x);
    }
    LL query(LL x,LL a,LL b){
        if(T[x].a>=a&&T[x].b<=b)return T[x].sum;
        if(T[x].tag)pb(x);LL mid=(T[x].a+T[x].b)>>1,res=0;
        if(mid>=a&&T[x].l)res+=query(T[x].l,a,b);
        if(mid<b&&T[x].r)res+=query(T[x].r,a,b); 
        return res;
    }
    LL chain(int x,int y){
        LL res=0;
        for(;top[x]!=top[y];x=f[top[x]]){
            if(d[top[x]]<d[top[y]]){int z=x;x=y;y=z;}
            res+=query(1,st[top[x]],st[x]);
        }if(d[x]<d[y]){int z=x;x=y;y=z;}
        res+=query(1,st[y],st[x]);
        return res;
    }
    int op;
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",a+i);
        for(int i=1;i<n;i++){
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }dfs(1);dfs2(1,1);
        build(1,dfn);
        for(int i=1;i<=n;i++)change(1,st[i],st[i],a[i]);
        for(int i=1;i<=m;i++){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d",&x,&y);
                change(1,st[x],st[x],y);
            }else if(op==2){
                scanf("%d%d",&x,&y);
                change(1,st[x],en[x],y);
            }else{
                scanf("%d",&x);
                printf("%lld
    ",chain(1,x));
            }
        }return 0;
    }
    

      

  • 相关阅读:
    设置navigationbar透明度时的坑
    NSOprationQueue 与 GCD 的区别与选用
    CALayer及其子类
    ARC基本原理
    drawRect:和layoutSubview的区别
    NSDictionary 和NSArray 排序(sort)
    iOS常用动画
    项目托管到Github上
    解析歌词
    计算字符串的长度值
  • 原文地址:https://www.cnblogs.com/forever97/p/BZOJ4034.html
Copyright © 2011-2022 走看看