zoukankan      html  css  js  c++  java
  • bzoj4034 树上操作 树链剖分+线段树

    题目传送门

    题目大意:

    有一棵点数为 N 的树,以点 1 为根,且树点有权。然后有 M 个操作,分为三种:
    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
     
    思路:
      由于是在刷dfs序专题的时候碰到这题,所以思路被限制了,没想树链剖分的东西,没能做出来,后来发现了一个 大佬的博客,发现也是可以做的,但是这个做法看不懂。。。留坑
      现在用树链剖分的方法,每个点的权值就是点本身的权值,对于1和2两种操作,直接使用线段树修改就可以了,无非是单点和区间的区别,这里推荐用线段树版本的树链剖分,虽然线段树比树状数组长很多,但是不需要考虑一些边界值加加减减的问题,比赛的时候想那个很可能犯错,用线段树来修改就简单多了(大佬无视这句话)。
      而对于查询操作,用的也是树链剖分往上跳的方法,每次都跳到重链,然后把这段区间的值加起来,(由于是重链,所以dfs序是连续的),这样就可以通过log(n)的时间得到链的权重了。
      所以除了这一点就是个树链剖分的模板题了,线段树直接网上找了一个板子,一发A,做题还是太少。
    #include<cstdio>
    #include<algorithm>
    //#include<iostream>
    #include<vector>
    #include<map>
    #include<set>
    #include<cstring>
    #include<queue>
    #include<stack>
    #include<stdlib.h>
    //#include<unordered_map>
    #define lson (o<<1)
    #define rson ((o<<1)|1)
    #define CLR(a,b) memset(a,b,sizeof(a))
    #define mkp(a,b) make_pair(a,b)
    typedef long long ll;
    using namespace std;
    const int maxn=100010;
    vector<int> edge[maxn];
    int n,m,op,x,tot,val[maxn],l[maxn],r[maxn],deep[maxn],son[maxn],fa[maxn],top[maxn],fin[maxn];
    ll sum[maxn<<3],lazy[maxn<<3],size[maxn<<3];
    inline void dfs_1(int x,int pre)
    {
        fa[x] = pre;
        son[x] = -1;
        size[x] = 1;
        deep[x] = deep[pre]+1;
        for(int i = 0; i < edge[x].size(); i++)
            if(edge[x][i] != pre)
            {
                dfs_1(edge[x][i],x);
                size[x] += size[edge[x][i]];
                if(son[x]==-1 || size[edge[x][i]]>size[son[x]]) son[x] = edge[x][i];
            }
    }
    inline void dfs_2(int x,int root)
    {
        top[x] = root;
        l[x]  = ++tot;
        fin[l[x]] = x;
        if(son[x] != -1)
        dfs_2(son[x],root);
        for(int i = 0; i < edge[x].size(); i++)
            if(edge[x][i] != fa[x] && edge[x][i] != son[x])
                dfs_2(edge[x][i],edge[x][i]);
        r[x]=tot;
    }
    inline void maintain(int o,int l,int r)
    {
        if(l!=r)sum[o]=sum[lson]+sum[rson];
    }
    inline void pushdown(int o,int l,int r)
    {
        if(lazy[o])
        {
            sum[lson]+=size[lson]*lazy[o];
            sum[rson]+=size[rson]*lazy[o];
            lazy[lson]+=lazy[o];
            lazy[rson]+=lazy[o];
        }
        lazy[o]=0;
    }
    inline void build(int o,int l,int r)
    {
        if(l==r)
        {
            sum[o]=(ll)val[fin[l]];
            size[o]=1;
            return;
        }
        int mid = (l+r)/2;
        build(lson,l,mid);
        build(rson,mid+1,r);
        maintain(o,l,r);
        size[o]=size[lson]+size[rson];
    }
    inline void update(int o,int l,int r,int L,int R,int v)
    {
        pushdown(o,l,r);
        if(R<l || L>r)return;
        if(l>=L && r<=R)
        {
            lazy[o]+=(ll)v;
            sum[o]+=((ll)size[o])*((ll)v);
            return;
        }
        int mid=(l+r)>>1;
        update(lson,l,mid,L,R,v);
        update(rson,mid+1,r,L,R,v);
        maintain(o,l,r);
    }
    inline ll query(int o,int l,int r,int L,int R)
    {
        pushdown(o,l,r);
        if(R<l || L>r)return 0;
        if(l>=L && r<=R)return sum[o];
        int mid=(l+r)>>1;
        return query(lson,l,mid,L,R)+query(rson,mid+1,r,L,R);
    }
    inline ll get(int x)
    {
        ll ret = 0;
        while(top[x]!=1)
        {
            ret+=query(1,1,n,l[top[x]],l[x]);
            x=fa[top[x]];
        }
        ret+=query(1,1,n,1,l[x]);
        return ret;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
            scanf("%d",&val[i]),sum[i]=i;
        int u,v;
        for(int i = 1; i < n; i++)
        {
            scanf("%d%d",&u,&v);
            edge[u].push_back(v);
            edge[v].push_back(u);
        }
        dfs_1(1,0);
        dfs_2(1,1);
        build(1,1,n);
        for(int i = 0; i < m; i++)
        {
            scanf("%d%d",&op,&x);
            if(op==1)
            {
                scanf("%d",&v);
                update(1,1,n,l[x],l[x],v);
            }
            if(op==2)
            {
                scanf("%d",&v);
                update(1,1,n,l[x],r[x],v);
            }
            if(op==3)printf("%lld
    ",get(x));
        }
        return 0;
    }
  • 相关阅读:
    python3的pygame的五子棋布局设置和代码详细分析
    RAID原理分析
    Python攻城狮教你用Pythin开机和关机,关机只需一条执行命令
    Python 之 MySql 每日一练 329——查询名字中含有风字的学生信息
    Python 之 MySql 每日一练 232——查询每门课程的平均成绩
    网络虚拟化基础协议·Geneve
    openstack octavia的实现与分析(一)openstack负载均衡的现状与发展以及lvs,Nginx,Haproxy三种负载均衡机制的基本架构和对比
    Linux下多网卡绑定bond及模式介绍
    Python调试器-pdb的使用
    ubuntu server安装的一些坑
  • 原文地址:https://www.cnblogs.com/mountaink/p/9886628.html
Copyright © 2011-2022 走看看