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. 洛谷3933 Chtholly Nota Seniorious 二分答案+贪心

    题目链接 题意 给你一个N*M的矩阵 (N,M <=2000)  把他分成两部分 使两部分的极差较大的一个最小  求这个最小值.然后分矩阵的要求是:每个部分内部的方块之间,可以通过上下左右相互到 ...

  2. bzoj1604 牛的邻居 STL

    Description 了解奶牛们的人都知道,奶牛喜欢成群结队.观察约翰的N(1≤N≤100000)只奶牛,你会发现她们已经结成了几个“群”.每只奶牛在吃草的时候有一个独一无二的位置坐标Xi,Yi(l ...

  3. 洛谷 P1454 圣诞夜的极光

    P1454 圣诞夜的极光 题目背景 圣诞夜系列~~ 题目描述 圣诞老人回到了北极圣诞区,已经快到12点了.也就是说极光表演要开始了.这里的极光不是极地特有的自然极光景象.而是圣诞老人主持的人造极光. ...

  4. Docker入门实践(三) 基本操作

    Docker安装完毕.我们就能够试着来执行一些命令了.看看docker能够干什么. (一) 创建一个容器 首先.让我们执行一个最简单的容器,hello-world.假设安装没有问题.并执行正确的话,应 ...

  5. iOS 动画Animation - 5:UIBezier

    首先说明:这是一系列文章,參考本专题下其它的文章有助于你对本文的理解. 在之前的bolg中大家会发现总是会出现UIBezier,可是我也没有做过多介绍,今天就集中介绍一下UIBezier.首先.UIB ...

  6. Project Euler:Problem 58 Spiral primes

    Starting with 1 and spiralling anticlockwise in the following way, a square spiral with side length ...

  7. powerpoint(ppt) 的制作

    1. 幻灯片母版 所谓母版,是共享的部分,也即想在全部幻灯片重复出现的元素. 首先,幻灯片母版在菜单栏的[视图]选择[幻灯片母版]显示和查看. 通过幻灯片母版的编辑和设计,可进一步: 在幻灯片的相关位 ...

  8. Android 使用Retrofit请求API数据

    概览 Retrofit 是一个Square开发的类型安全的REST安卓客户端请求库.这个库为网络认证.API请求以及用OkHttp发送网络请求提供了强大的框架 .理解OkHttp 的工作流程见  这个 ...

  9. HP 1022N 网络打印机安装步骤

    HP 1022N 网络打印机安装步骤

  10. python 批量下载文件

    file.txt 的内容为: http://183.xxx.xxx.54:188/my/qqq.ico::qq.exe::0::http://183.xxx.xxx.54:186/my/ddnf.ic ...