bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 4352 Solved: 1387
[Submit][Status][Discuss]
Description
Input
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
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
Sample Output
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
思路:由于有3的操作,很容易想到树链剖分,2怎么办?
对于树链剖分来说,其子树中的节点,也是连续的,所以找子树中编号最大的;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstring>
#include<vector>
#include<list>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define pi (4*atan(1.0))
#define eps 1e-14
#define bug(x) cout<<"bug"<<x<<endl;
const int N=1e5+,M=1e6+,inf=1e9+;
const ll INF=1e18+,mod=; ///数组大小
struct edge
{
int v,next;
} edge[N<<];
int head[N<<],edg,id,n;
/// 树链剖分 int fa[N],dep[N],son[N],siz[N]; // fa父亲,dep深度,son重儿子,siz以该点为子树的节点个数
int a[N],ran[N],top[N],tid[N],mx[N]; // tid表示边的标号,top通过重边可以到达最上面的点,ran表示标记tid
void init()
{
memset(son,-,sizeof(son));
memset(head,-,sizeof(head));
edg=;
id=;
} void add(int u,int v)
{
edg++;
edge[edg].v=v;
edge[edg].next=head[u];
head[u]=edg;
} void dfs1(int u,int fath,int deep)
{
fa[u]=fath;
siz[u]=;
dep[u]=deep;
for(int i=head[u]; i!=-; i=edge[i].next)
{
int v=edge[i].v;
if(v==fath)continue;
dfs1(v,u,deep+);
siz[u]+=siz[v];
if(son[u]==-||siz[v]>siz[son[u]])
son[u]=v;
}
} void dfs2(int u,int tp)
{
tid[u]=mx[u]=++id;
top[u]=tp;
ran[tid[u]]=u;
if(son[u]==-)return;
dfs2(son[u],tp),mx[u]=max(mx[u],mx[son[u]]);
for(int i=head[u]; i!=-; i=edge[i].next)
{
int v=edge[i].v;
if(v==fa[u])continue;
if(v!=son[u])
dfs2(v,v),mx[u]=max(mx[u],mx[v]);
}
} struct SGT
{
ll sum[N<<],lazy[N<<];
void pushup(int pos)
{
sum[pos]=sum[pos<<]+sum[pos<<|];
}
void pushdown(int pos,int l,int r)
{
if(lazy[pos])
{
int mid=(l+r)>>;
lazy[pos<<]+=lazy[pos];
lazy[pos<<|]+=lazy[pos];
sum[pos<<]+=lazy[pos]*(mid-l+);
sum[pos<<|]+=lazy[pos]*(r-mid);
lazy[pos]=;
}
}
void build(int l,int r,int pos)
{
lazy[pos]=;
if(l==r)
{
sum[pos]=a[ran[l]];
return;
}
int mid=(l+r)>>;
build(l,mid,pos<<);
build(mid+,r,pos<<|);
pushup(pos);
}
void update(int L,int R,ll c,int l,int r,int pos)
{
if(L<=l&&r<=R)
{
sum[pos]+=c*(r-l+);
lazy[pos]+=c;
return;
}
pushdown(pos,l,r);
int mid=(l+r)>>;
if(L<=mid)update(L,R,c,l,mid,pos<<);
if(R>mid) update(L,R,c,mid+,r,pos<<|);
pushup(pos);
}
ll query(int L,int R,int l,int r,int pos)
{
if(L<=l&&r<=R)return sum[pos];
pushdown(pos,l,r);
int mid=(l+r)>>;
ll ans=;
if(L<=mid)ans+=query(L,R,l,mid,pos<<);
if(R>mid)ans+=query(L,R,mid+,r,pos<<|);
return ans;
}
}tree; ll up(int l,int r)
{
ll ans=;
while(top[l]!=top[r])
{
if(dep[top[l]]<dep[top[r]])swap(l,r);
ans+=tree.query(tid[top[l]],tid[l],,n,);
l=fa[top[l]];
}
if(dep[l]<dep[r])swap(l,r);
ans+=tree.query(tid[r],tid[l],,n,);
return ans;
} int main()
{
init();
int q;
scanf("%d%d",&n,&q);
for(int i=; i<=n; i++)
scanf("%d",&a[i]);
for(int i=; i<n; i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs1(,-,);
dfs2(,);
tree.build(,n,);
while(q--)
{
int t,x;
scanf("%d%d",&t,&x);
if(t==)
{
ll z;
scanf("%lld",&z);
tree.update(tid[x],tid[x],z,,n,);
}
else if(t==)
{
ll z;
scanf("%lld",&z);
tree.update(tid[x],mx[x],z,,n,);
}
else
printf("%lld\n",up(,x));
}
return ;
}
bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树的更多相关文章
- BZOJ 4034: [HAOI2015]树上操作 [欧拉序列 线段树]
题意: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 显然树链剖分可做 ...
- BZOJ 4034 [HAOI2015]树上操作(欧拉序+线段树)
题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- BZOJ 3589 动态树 (树链剖分+线段树)
前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- bzoj 2157: 旅游【树链剖分+线段树】
裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
随机推荐
- [转载]Oracle左连接、右连接、全外连接以及(+)号用法
Oracle 外连接(OUTER JOIN) 左外连接(左边的表不加限制) 右外连接(右边的表不加限制) 全外连接(左右两表都不加限制) 对应SQL:LEFT/RIGHT/FULL OUTER JO ...
- Python+OpenCV图像处理(二)——打印图片属性、设置图片存储路径、电脑摄像头的调取和显示
一. 打印图片属性.设置图片存储路径 代码如下: #打印图片的属性.保存图片位置 import cv2 as cv import numpy as np #numpy是一个开源的Python科学计算库 ...
- Python基础(一)_数据类型、条件判断、循环、列表
编译型语言(中文版)运行代码之前,要先编译.然后再运行编译时间比较长c.c++.c# 解释型语言(翻译版)运行的时候才去编译,运行一次编译.运行效率没有编译型语言快python.ruby.shell. ...
- kali linux DIY
开启你的kali linux DIY之旅 感谢原博主的分享,真的非常非常受用! 更新源 首先 是kali2016.2更新源的问题,网上找了好久,都不是很满意.后来把kali 2016.2安装到实体机中 ...
- Action的编写方式
四.Action 的编写方式 : 三种 第一种 创建普通类 不继承任何类,不实现任何接口 Public class HelloAction{ } 第二种 创建类,实现接口action Public ...
- 使用Selenium和openCV对HTML5 canvas游戏进行自动化功能测试(一)
上一篇讲了HTML5 canvas游戏的基本工作原理,接下来讲如何进行自动化功能测试. Selenium是一个跨平台的跨浏览器的对网页进行自动化测试的工具.从Selenium 2.0开始Seleniu ...
- KPI 私有CA
openssl总结及私有CA的搭建 搭建CA服务器 CA(证书颁发机构)服务器配置图解过程(1) 私有CA服务器的搭建 搭建CA服务器 使用OpenSSL搭建CA Linux加密和解密.openssl ...
- shell脚本一键安装nginx
依赖包安装包放在一起, 直接执行这个脚本就行. #!/bin/bash #--------------------------------------------------------------- ...
- python之路-day1-if...else...流程判断
判断输入的用户名:#Author:zww _username = "zww" _password = " username = input("username: ...
- 20145208 蔡野 《网络对抗》Exp6 信息搜集与漏洞扫描
20145208 蔡野 <网络对抗>Exp6 信息搜集与漏洞扫描 本实践的目标是掌握信息搜集的最基础技能.具体有(1)各种搜索技巧的应用(2)DNS IP注册信息的查询 (3)基本的扫描技 ...