BZOJ4034 [HAOI2015]T2 题解&代码

原创 2016年06月01日 21:32:05

题意: 有一棵有N个节点的树,以节点1为根,且点上有权。
有M个操作,分为三种:
操作 1 把节点x的点权增加 a
操作 2 把以节点x为根的树中所有点的点权都增加a
操作 3 求节点x到根的路径中所有点的点权和

分析:
操作1和操作2本质上是没有区别的,区间修改和单点修改显然可以合并,求dfs序后线段树区间维护就可以了
操作3是涉及路径的查询,和树剖很类似,但是比树剖简单很多【比如我求的deep完全没有用2333333】,按照树剖的思路分段查询即可

note:
线段树八倍空间!不然会迷之RE!明明四倍理论上是可以的QAQ
最开始初始化忘记初始化size[]了…于是各种算错233333我个智障

/**************************************************************
    Problem: 4034
    User: Rainbow6174
    Language: C++
    Result: Accepted
    Time:3920 ms
    Memory:29872 kb
****************************************************************/

#include<iostream>
#include<vector>
#include<cstdio>
#define lson (o<<1)
#define rson ((o<<1)|1)
#define LL long long
using namespace std;
const int maxn = 100005;
vector<int> edge[maxn];
int n,m,op,x,tot,val[maxn],in[maxn],out[maxn],deep[maxn],son[maxn],fa[maxn],rt[maxn],fin[maxn];
LL sum[8*maxn],lazy[8*maxn],size[8*maxn];
void dfs1(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)
        {
            dfs1(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];
        }
}
void dfs2(int x,int root)
{
    rt[x] = root;
    in[x] = out[x] = ++tot;
    fin[in[x]] = x;
    if(son[x] != -1)dfs2(son[x],root);
    for(int i = 0; i < edge[x].size(); i++)
        if(edge[x][i] != fa[x] && edge[x][i] != son[x])
            dfs2(edge[x][i],edge[x][i]);
    out[x]=tot;
}
void maintain(int o,int l,int r)
{
    if(l!=r)sum[o]=sum[lson]+sum[rson];
}
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;
}
void build(int o,int l,int r)
{
    if(l==r)
    {
        sum[o]=(LL)val[fin[l]];
        size[o]=1;
        //cout<<o<<' '<<sum[o]<<endl;
        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];
}
void addtree(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);
        //cout<<"test "<<o<<' '<<l<<' '<<r<<' '<<sum[o]<<endl;
        return;
    }
    int mid=(l+r)>>1;
    addtree(lson,l,mid,L,R,v);
    addtree(rson,mid+1,r,L,R,v);
    maintain(o,l,r);
}
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);
}
LL Query(int x)
{
    LL ret = 0;
    while(rt[x]!=1)
    {
        ret+=query(1,1,n,in[rt[x]],in[x]);
        x=fa[rt[x]];
    }
    ret+=query(1,1,n,1,in[x]);
    return ret;
}
int main(void)
{
    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);
    }
    dfs1(1,0);dfs2(1,1);
    build(1,1,n);
    for(int i = 0; i < m; i++)
    {
        scanf("%d%d",&op,&x);
        if(op==1)
        {
            scanf("%d",&v);
            addtree(1,1,n,in[x],in[x],v);
        }
        if(op==2)
        {
            scanf("%d",&v);
            addtree(1,1,n,in[x],out[x],v);
        }
        if(op==3)printf("%lld\n",Query(x));
    }
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

bzoj4034[HAOI2015]T2 - 树链剖分

题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=4034 题目意思: 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 ...

Bzoj4034:[HAOI2015]T2:树链剖分

题目链接:4034:[HAOI2015]T2 水树链剖分,注意开long long…… #include #include #include #include #define LL long lo...

BZOJ 4034 [HAOI2015]T2 树链剖分+线段树

BZOJ 4034 [HAOI2015]T2 树链剖分+线段树

bzoj 4034: [HAOI2015]T2

Description  有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a 。 操作 2 :把某个节点 x...

BZOJ 4034 [HAOI2015]T2 树链剖分

Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a 。 操...

bzoj4034: [HAOI2015]T2

初学树剖。。。听说是裸题。。。然后就做了。。。 注意某个节点和它的子树DFS序相连,只要记住它子树最大的DFS序即可进行子树修改。 #include #include #define N 200000...

[BZOJ 4034][HAOI2015]T2 [树链剖分]

要锻炼静态查错能力。orz。 update里面忘了pushdown() 了。尴尬。#include #include #include #include #include #include usin...

bzoj 4034 [HAOI2015]T2 树链剖分+线段树

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4034题解:树上单点修改+子树修改+链查询 单点修改和链的查询都属于裸的树链剖分,比较好想,...

BZOJ 4034 [HAOI2015]T2

树剖+线段树要能够一次性给子树赋值,可以用DFS序+线段树 要查询点到根的路径和,树剖+线段树 于是用树剖的DFS序建树#include #define N 100005 #define ll l...

BZOJ 4034: [HAOI2015]T2|线段树|树链剖分

写完裸的熟练剖分后,发现似乎不用树剖,只用dfs序就可以 然后就又写了一发,样例都过不了,发现是个错的………………………… 熟练剖分对于此题算是最裸的写法了 单点修改,直接在线段树中暴力改这一个点...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)