树链剖分【p3178】[HAOI2015]树上操作
Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
明显的树剖裸题,不过没有一遍切掉就很可惜.
貌似只有边权转点权的时候需要判断\(x==y\)?
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
#define int long long
#define R register
#define N 100008
using namespace std;
inline void in(int &x)
{
	int f=1;x=0;char s=getchar();
	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
	x*=f;
}
int n,m,head[N],tot,f[N],son[N],size[N],depth[N];
struct cod{int u,v;}edge[N<<2];
inline void add(int x,int y)
{
	edge[++tot].u=head[x];
	edge[tot].v=y;
	head[x]=tot;
}
void dfs1(int u,int fa)
{
	f[u]=fa;depth[u]=depth[fa]+1;size[u]=1;
	for(R int i=head[u];i;i=edge[i].u)
	{
		if(edge[i].v==fa)continue;
		dfs1(edge[i].v,u);
		size[u]+=size[edge[i].v];
		if(son[u]==-1 or size[son[u]]<size[edge[i].v])
			son[u]=edge[i].v;
	}
}
int idx,dfn[N],fdfn[N],top[N];
void dfs2(int u,int t)
{
	top[u]=t;dfn[u]=++idx;fdfn[idx]=u;
	if(son[u]==-1)return;
	dfs2(son[u],t);
	for(R int i=head[u];i;i=edge[i].u)
	{
		if(dfn[edge[i].v])continue;
		dfs2(edge[i].v,edge[i].v);
	}
}
#define ls o<<1
#define rs o<<1|1
int tr[N<<2],tg[N<<2],a[N];
inline void up(int o){tr[o]=tr[ls]+tr[rs];}
inline void down(int o,int l,int r)
{
	if(tg[o])
	{
		int mid=(l+r)>>1;
		tg[ls]+=tg[o];tg[rs]+=tg[o];
		tr[ls]+=(mid-l+1)*tg[o];
		tr[rs]+=(r-mid)*tg[o];
		tg[o]=0;
	}
}
void build(int o,int l,int r)
{
	if(l==r)
	{
		tr[o]=a[fdfn[l]];
		return;
	}
	int mid=(l+r)>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
	up(o);
}
void change(int o,int l,int r,int x,int y,int z)
{
	if(x<=l and y>=r)
	{
		tg[o]+=z;
		tr[o]+=(r-l+1)*z;
		return;
	}
	down(o,l,r);
	int mid=(l+r)>>1;
	if(x<=mid)change(ls,l,mid,x,y,z);
	if(y>mid) change(rs,mid+1,r,x,y,z);
	up(o);
}
int query(int o,int l,int r,int x,int y)
{
	if(x<=l and y>=r)return tr[o];
	down(o,l,r);
	int mid=(l+r)>>1,res=0;
	if(x<=mid) res+=query(ls,l,mid,x,y);
	if(y>mid)res+=query(rs,mid+1,r,x,y);
	return res;
}
int tquery(int x,int y)
{
	int fx=top[x],fy=top[y],res=0;
	while(fx!=fy)
	{
		if(depth[fx]>depth[fy])
		{
			res+=query(1,1,idx,dfn[fx],dfn[x]);
			x=f[fx];
		}
		else
		{
			res+=query(1,1,idx,dfn[fy],dfn[y]);
			y=f[fy];
		}
		fx=top[x],fy=top[y];
	}
	if(dfn[x]>dfn[y])swap(x,y);
	res+=query(1,1,idx,dfn[x],dfn[y]);
	return res;
}
signed main()
{
	in(n),in(m);memset(son,-1,sizeof son);
	for(R int i=1;i<=n;i++)in(a[i]);
	for(R int i=1,x,y;i<n;i++)
	{
		in(x),in(y);
		add(x,y);add(y,x);
	}
	dfs1(1,0);dfs2(1,1);build(1,1,n);
	for(R int opt,x,y;m;m--)
	{
		in(opt);
		if(opt==1)
		{
			in(x),in(y);
			change(1,1,n,dfn[x],dfn[x],y);
		}
		if(opt==2)
		{
			in(x),in(y);
			change(1,1,n,dfn[x],dfn[x]+size[x]-1,y);
		}
		if(opt==3)
		{
			in(x);
			printf("%lld\n",tquery(1,x));
		}
	}
}
												
											树链剖分【p3178】[HAOI2015]树上操作的更多相关文章
- 洛谷P3178 [HAOI2015]树上操作(dfs序+线段树)
		
P3178 [HAOI2015]树上操作 题目链接:https://www.luogu.org/problemnew/show/P3178 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边 ...
 - P3178 [HAOI2015]树上操作
		
P3178 [HAOI2015]树上操作 思路 板子嘛,其实我感觉树剖没啥脑子 就是debug 代码 #include <bits/stdc++.h> #define int long l ...
 - 洛谷P3178 [HAOI2015]树上操作 题解 树链剖分+线段树
		
题目链接:https://www.luogu.org/problem/P3178 这道题目是一道树链剖分的模板题. 但是在解决这道问题的同事刷新了我的两个认识: 第一个认识是:树链剖分不光可以处理链, ...
 - 洛谷P3178 [HAOI2015]树上操作
		
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...
 - LUOGU P3178 [HAOI2015]树上操作
		
传送门 解题思路 树链剖分裸题,线段树维护. 代码 #include<iostream> #include<cstdio> #include<cstring> #d ...
 - P3178 [HAOI2015]树上操作 树链剖分
		
这个题就是一道树链剖分的裸题,但是需要有一个魔性操作___编号数组需要开longlong!!!震惊!真的神奇. 题干: 题目描述 有一棵点数为 N 的树,以点 为根,且树点有边权.然后有 M 个操作, ...
 - 洛谷P3178 [HAOI2015]树上操作(线段树)
		
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...
 - 洛谷 P3178 [HAOI2015]树上操作
		
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...
 - 洛谷——P3178 [HAOI2015]树上操作
		
https://www.luogu.org/problem/show?pid=3178#sub 题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 ...
 - 【luogu P3178 [HAOI2015]树上操作】 题解
		
题目链接:https://www.luogu.org/problemnew/show/P3178 模板题 菜 #include <cstdio> #include <cstring& ...
 
随机推荐
- 孤荷凌寒自学python第五十五天初识MongoDb数据库
			
孤荷凌寒自学python第五十五天第一天初识MongoDb数据库 (完整学习过程屏幕记录视频地址在文末) 大家好,2019年新年快乐! 本来我想的是借新年第一天开始,正式尝试学习爬虫,结果今天偶然发现 ...
 - Python读取不同文件夹下的图片并且分类放到新创建的训练文件夹和标签文件夹
			
在深度学习的训练时,经常会碰到训练的样本数据集和标签数据集是在一个文件夹中,这个时候我们就不得不进行一些数据的预处理和文件的分类,例如将训练(training data)数据集和标签数据集(label ...
 - atom下python好用的几个插件
			
atom下python好用的几个插件 atom-beautify 代码优化 atom-python-run 运行 autocomplete-python 代码补全 file-icons 图标优化 hi ...
 - altium designer同一工程多个原理图如何快速查找同一网络标号
			
方法一:如果只知道网络标号的名称,尚未找到任何一个,可以:Ctrl+F,输入网络标号名称,可按顺序逐个查看各个网络标号. 方法二:如果已经看到一个所要查找的网络标号,可以:按住Alt键不放,鼠标左键单 ...
 - Java面试题之CyclicBarrier和CountDownLatch的区别
			
1.CyclicBarrier的某个线程运行到某个点后停止运行,直到所有线程都达到同一个点,所有线程才会重新运行: CountDownLatch线程运行到某个点后,计数值-1,该线程继续运行,直到计数 ...
 - mysql 查询结果创建表
			
用 SELECT 的结果创建表 关系数据库的一个重要概念是,任何数据都表示为行和列组成的表,而每条 SELECT 语句的结果也都是一个行和列组成的表.在许多情况下,来自 SELECT 的“表”仅是一个 ...
 - 转:ExecutorService
			
在Java5之后,并发线程这块发生了根本的变化,最重要的莫过于新的启动.调度.管理线程的一大堆API了.在Java5以后,通过 Executor来启动线程比用Thread的start()更好.在新特征 ...
 - 自定义Windows服务并实施安装
			
1.新建项目DemoService,并添加windows服务,命名DemoService 2.添加代码 using System; using System.Collections.Generic; ...
 - [ CodeVS冲杯之路 ] P1116
			
不充钱,你怎么AC? 题目:http://codevs.cn/problem/1116/ 数据很小,DFS可A,每层枚举颜色,判断相邻的点是否有重复的颜色,记得回溯时把颜色染回0,即无颜色 这里我使用 ...
 - jQuery选择器总结(重要)
			
jQuery 的选择器可谓之强大无比,这里简单地总结一下常用的元素查找方法 $("#myELement") 选择id值等于myElement的元素,id值不能重复在文档中只能有一个 ...