https://www.luogu.org/problem/show?pid=3178#sub

题目描述

有一棵点数为 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 ) 。

输出格式:

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

输入输出样例

输入样例#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 <algorithm>
#include <cstdio> #define LL long long using namespace std; const LL N(+);
const LL M(+);
LL n,m,u,v,w,op,val[N]; LL head[N],sumedge;
struct Edge
{
LL u,v,next;
Edge(LL u=,LL v=,LL next=):
u(u),v(v),next(next){}
}edge[M<<];
inline void ins(LL u,LL v)
{
edge[++sumedge]=Edge(u,v,head[u]);
head[u]=sumedge;
} LL size[N],deep[N],dad[N],son[N],top[N],dfn[N],id[N],cnt;
void DFS(LL x,LL father,LL deepth)
{
deep[x]=deepth;
dad[x]=father;
size[x]=;
for(LL i=head[x];i;i=edge[i].next)
{
LL v=edge[i].v;
if(dad[x]==v) continue;
DFS(v,x,deepth+);
size[x]+=size[v];
if(size[son[x]]<size[v]) son[x]=v;
}
}
void DFS_(LL x,LL Top)
{
top[x]=Top;
id[x]=++cnt,dfn[cnt]=x;
if(son[x]) DFS_(son[x],Top);
for(LL i=head[x];i;i=edge[i].next)
{
LL v=edge[i].v;
if(dad[x]!=v&&son[x]!=v) DFS_(v,v);
}
} struct Tree
{
LL l,r,mid,flag,val;
}tree[N<<];
inline void Tree_up(LL now)
{
tree[now].val=tree[now<<].val+tree[now<<|].val;
}
void Tree_down(LL now)
{
tree[now<<].flag+=tree[now].flag;
tree[now<<].val+=(tree[now].mid-tree[now].l+)*tree[now].flag;
tree[now<<|].flag+=tree[now].flag;
tree[now<<|].val+=(tree[now].r-tree[now].mid)*tree[now].flag;
tree[now].flag=;
}
void Tree_build(LL now,LL l,LL r)
{
tree[now].l=l;tree[now].r=r;
if(l==r)
{
tree[now].val=val[dfn[l]];
return ;
}
tree[now].mid=l+r>>;
Tree_build(now<<,l,tree[now].mid);
Tree_build(now<<|,tree[now].mid+,r);
Tree_up(now);
}
void Tree_change(LL now,LL l,LL r,LL x)
{ if(tree[now].l==l&&tree[now].r==r)
{
tree[now].flag+=x;
tree[now].val+=(r-l+)*x;
return ;
}
if(tree[now].flag) Tree_down(now);
if(tree[now].mid>=r) Tree_change(now<<,l,r,x);
else if(tree[now].mid<l) Tree_change(now<<|,l,r,x);
else
{
Tree_change(now<<,l,tree[now].mid,x);
Tree_change(now<<|,tree[now].mid+,r,x);
}
Tree_up(now);
}
LL Tree_query(LL now,int l,int r)
{
if(tree[now].l==l&&tree[now].r==r)
return tree[now].val;
if(tree[now].flag) Tree_down(now);
if(tree[now].mid>=r) return Tree_query(now<<,l,r);
else if(tree[now].mid<l) return Tree_query(now<<|,l,r);
else return Tree_query(now<<,l,tree[now].mid)+Tree_query(now<<|,tree[now].mid+,r);
} LL List_query(LL x,LL y)
{
LL ret=;
for(;top[x]!=top[y];x=dad[top[x]])
{
if(deep[top[x]]<deep[top[y]]) swap(x,y);
ret+=Tree_query(,id[top[x]],id[x]);
}
if(deep[x]<deep[y]) swap(x,y);
ret+=Tree_query(,id[y],id[x]);
return ret;
} int if_,ch;
inline void read (LL &x)
{
if_=x=;ch=getchar();
for(;ch<''||ch>'';ch=getchar())
if(ch=='-') if_=;
for(;ch>=''&&ch<='';ch=getchar())
x=x*+ch-'';
if(if_) x=(~x)+;
} int main()
{
read(n); read(m);
for(LL i=;i<=n;i++)
read(val[i]);
for(LL i=;i<n;i++)
{
read(u); read(v);
ins(u,v),ins(v,u);
}
DFS(,,);DFS_(,);
Tree_build(,,n);
for(;m--;)
{
read(op);
if(op==)
{
read(u); read(w);
Tree_change(,id[u],id[u],w);
}
else if(op==)
{
read(u); read(w);
Tree_change(,id[u],id[u]+size[u]-,w);
}
else
{
read(u);
printf("%lld\n",List_query(u,));
}
}
return ;
}

洛谷——P3178 [HAOI2015]树上操作的更多相关文章

  1. 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)

    P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...

  2. 洛谷P3178 [HAOI2015]树上操作 题解 树链剖分+线段树

    题目链接:https://www.luogu.org/problem/P3178 这道题目是一道树链剖分的模板题. 但是在解决这道问题的同事刷新了我的两个认识: 第一个认识是:树链剖分不光可以处理链, ...

  3. 洛谷P3178 [HAOI2015]树上操作

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...

  4. 洛谷P3178 [HAOI2015]树上操作(线段树)

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...

  5. 洛谷 P3178 [HAOI2015]树上操作

    题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...

  6. 洛谷 3178 [HAOI2015]树上操作

    [题解] 就是个树链剖分的模板题. #include<cstdio> #include<algorithm> #include<cstring> #define L ...

  7. P3178 [HAOI2015]树上操作

    P3178 [HAOI2015]树上操作 思路 板子嘛,其实我感觉树剖没啥脑子 就是debug 代码 #include <bits/stdc++.h> #define int long l ...

  8. 洛谷 P3177 [HAOI2015]树上染色 树形DP

    洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...

  9. BZOJ4033或洛谷3177 [HAOI2015]树上染色

    BZOJ原题链接 洛谷原题链接 很明显的树形\(DP\). 因为记录每个点的贡献很难,所以我们可以统计每条边的贡献. 对于每一条边,设边一侧的黑点有\(B_x\)个,白点有\(W_x\),另一侧黑点有 ...

随机推荐

  1. JS文字特效:彩色滚动变幻效果,只适合少量的文字。(过多对页面有影响)

    JS代码如下: 代码具体是在哪里的我不知道但是我的有道云上有.如有哪位朋友知道,还望联系下,添加出处. <div id="chakhsu"></div> & ...

  2. BZOJ 2724 [Violet 6]蒲公英(分块)

    题意 在线区间众数 思路 预处理出 f[i][j] 即从第 i 块到第 j 块的答案.对于每个询问,中间的整块直接用预处理出的,两端的 sqrtn 级别的数暴力做,用二分查找它们出现的次数.每次询问的 ...

  3. 紫书 例题 10-12 UVa 1637(概率计算)

    以9元组来代表当前状态,每一元是每一堆剩下的牌数 枚举当前状态所有可以拿掉牌的情况,然后递归下去求 概率,当牌拿完的时候概率为1 那么这里的实现非常的秀,用到了vector来代表9元组 然后还用到了m ...

  4. STL_算法_局部排序(partial_sort、partial_sort_copy)

    C++ Primer 学习中. . . 简单记录下我的学习过程 (代码为主) /***************************************** // partial_sort(b, ...

  5. POJ 3450--Corporate Identity【KMP &amp;&amp; 枚举】

    Corporate Identity Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 5696   Accepted: 207 ...

  6. git commit template

    https://www.zhihu.com/question/27462267/answer/204658544 https://gist.github.com/adeekshith/cd4c95a0 ...

  7. 4.graph.h

    #pragma once #include <stdio.h> #include <graphics.h> #include <mmsystem.h> #pragm ...

  8. C# DevExpress GridControl使用方法

    一.如何解决单击记录整行选中的问题 View->OptionsBehavior->EditorShowMode 设置为:Click 二.如何新增一条记录 ().gridView.AddNe ...

  9. 使用iVMS-4200 存储录像数据时的设置

    1.安装软件时,选择:存储服务器 2.对存储服务器进行配置,具体配置见 配置手册.

  10. C/C++(C++重载,默认参数,引用)

    C++重载详解 重载就是同名而非同义,具体意义根据上下文的语境而言. 重载规则: 1,函数名相同. 2,参数个数不同,参数的类型不同,参数顺序不同,均可构成重载. 3,返回值类型不同则不可以构成重载. ...