BZOJ4034: [HAOI2015]树上操作
这题把我写吐了。。。代码水平还是太弱鸡了啊。。。
这题就是先给你一些点,以及点权。然后给你一些向边构成一颗树,树的根节点是1。
然后给定三个操作
第一个是把指定节点的权值+W
第二个是把指定节点X为根(包括自己)的所有点权+W
第三个是求出指定节点到根节点的点权之和
嗯没错,听了大佬讲,肯定跑不了是DFS序,那么是用哪种呢???是N的还是2N的??
我们思考一个问题,如果是N的,能表示什么遍历完成儿子节点的时间吗???显然不能
但是。。。2n的是可以的,因为节点DFS出现两次中间的节点都是他的儿子。
如果知道DFS序列,上面1.2操作显然是不足为虑的。。。但是3操作呢???我们如果单纯求和,那么有些没有走过的点会计算两次,
不妨这样考虑:我们写出DFS序

如果求5到根节点,我们会求出12(33)5,每个数前后的位置,我们可以用一个数组存储(这非常简单),我们能不能想办法消去这个影响呢???
这是没问题的,我来思考一下,如果我依照某个DFS序,到底起点,那么DFS序中出现两次的一定是没用的,我们统计内部内部只出现一次数的个数,这个些个数就是操作3在这个区间的效果。
但是还有一个问题,我们如果抵消了,那么是不是GG了?我以后访问这个数岂不是也完蛋了?但题目要求跟新的整个子树,我如果这样抵消。。。会对以后造成影响吗??
其实是不会的,因为我们是把加的值放在了这个数第一次出现的地方,把减的值放在了第二次出现的地方。我们实际上对后面不会有影响,如果要访问节点x以及其子树,一定不会访问到第二个节点x出现的位置。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
const int maxx = 1e6+;
struct node{
int l,r;
LL sum,laze;
}tree[maxx<<];
struct snode{
int pre,bac;
}id[maxx];
vector<int>G[maxx];
int vis[maxx];
int st[maxx];
int num[maxx],a[maxx],b[maxx],c[maxx];
int n,m;
int cnt;
int num_s;
inline int L(int x){return x<<;};
inline int R(int x){return x<<|;};
inline int MID(int l,int r){return (l+r)>>;};
void push_down(int root){
if (tree[root].laze){
tree[L(root)].laze+=tree[root].laze;
tree[R(root)].laze+=tree[root].laze;
tree[L(root)].sum+=(LL)(num[tree[L(root)].r]-num[tree[L(root)].l-])*tree[root].laze;
tree[R(root)].sum+=(LL)(num[tree[R(root)].r]-num[tree[R(root)].l-])*tree[root].laze;
tree[root].laze=;
}
}
void buildtree(int root,int l,int r){
tree[root].l=l;
tree[root].r=r;
tree[root].laze=;
tree[root].sum=;
if (l==r){
tree[root].sum=(LL)(num[l]-num[l-])*a[st[l]];
return;
}
int mid=MID(l,r);
buildtree(L(root),l,mid);
buildtree(R(root),mid+,r);
tree[root].sum=tree[L(root)].sum+tree[R(root)].sum;
}
void update(int root,int ul,int ur,int w){
int l=tree[root].l;
int r=tree[root].r;
if (ul<=l && r<=ur){
tree[root].sum+=(LL)(num[r]-num[l-])*w;
tree[root].laze+=w;
return;
}
push_down(root);
int mid=MID(l,r);
if (ur<=mid){
update(L(root),ul,ur,w);
}else if(ul>mid){
update(R(root),ul,ur,w);
}else{
update(L(root),ul,mid,w);
update(R(root),mid+,ur,w);
}
tree[root].sum=tree[L(root)].sum+tree[R(root)].sum;
}
LL query(int root,int ql,int qr){
int l=tree[root].l;
int r=tree[root].r;
int mid;
LL sum=;
if (ql<=l && r<=qr){
return tree[root].sum;
}
mid=MID(l,r);
push_down(root);
if (qr<=mid){
sum+=query(L(root),ql,qr);
}else if (ql>mid){
sum+=query(R(root),ql,qr);
}else {
sum+=query(L(root),ql,mid);
sum+=query(R(root),mid+,qr);
}
return sum;
}
void dfs(int x)
{
vis[x]=;
cnt++;
num[cnt]=;
st[cnt]=x;
c[x]=cnt;
id[x].pre=cnt;
for (int i=;i<G[x].size();i++)
{
if(!vis[G[x][i]]){
dfs(G[x][i]);
}
}
cnt++;
id[x].bac=cnt;
st[cnt]=x;
num[cnt]=-;
}
int main()
{
int u,v,op,tmp1,tmp2;
while(~scanf("%d%d",&n,&m))
{
for (int i=;i<=n;i++){
G[i].clear();
}
cnt=;
num_s=;
memset(vis,,sizeof(vis));
memset(tree,,sizeof(tree));
for (int i=;i<=n;i++){
scanf("%d",&a[i]);
}
for (int i=; i<n; i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs();
num[]=;
for (int i=;i<=*n;i++){
num[i]=num[i-]+num[i];
}
buildtree(,,*n);
while(m--){
scanf("%d",&op);
if (op==){
scanf("%d%d",&tmp1,&tmp2);
update(,id[tmp1].pre,id[tmp1].pre,tmp2);
update(,id[tmp1].bac,id[tmp1].bac,tmp2);
}else if (op==){
scanf("%d%d",&tmp1,&tmp2);
update(,id[tmp1].pre,id[tmp1].bac,tmp2);
}else {
scanf("%d",&tmp1);
printf("%lld\n",query(,,id[tmp1].pre));;
}
}
}
return ;
}
/* */
BZOJ4034: [HAOI2015]树上操作的更多相关文章
- bzoj千题计划242:bzoj4034: [HAOI2015]树上操作
http://www.lydsy.com/JudgeOnline/problem.php?id=4034 dfs序,树链剖分 #include<cstdio> #include<io ...
- bzoj4034[HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6163 Solved: 2025[Submit][Stat ...
- bzoj4034: [HAOI2015]树上操作(树剖)
4034: [HAOI2015]树上操作 题目:传送门 题解: 树剖裸题: 麻烦一点的就只有子树修改(其实一点也不),因为子树编号连续啊,直接改段(记录编号最小和最大) 开个long long 水模版 ...
- BZOJ4034 [HAOI2015]树上操作 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4034 题意概括 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三 ...
- BZOJ4034[HAOI2015]树上操作——树链剖分+线段树
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...
- [luogu3178][bzoj4034][HAOI2015]树上操作
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增 ...
- [bzoj4034][HAOI2015]树上操作——树状数组+dfs序
Brief Description 您需要设计一种数据结构支持以下操作: 把某个节点 x 的点权增加 a . 把某个节点 x 为根的子树中所有点的点权都增加 a . 询问某个节点 x 到根的路径中所有 ...
- BZOJ4034 [HAOI2015]树上操作+DFS序+线段树
参考:https://www.cnblogs.com/liyinggang/p/5965981.html 题意:是一个数据结构题,树上的,用dfs序,变成线性的: 思路:对于每一个节点x,记录其DFS ...
- bzoj4034 [HAOI2015]树上操作——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4034 树剖裸题: 一定要注意 long long !!! update 的时候别忘了 pus ...
随机推荐
- JavaScript(转载自 计科学院 慕课网)
什么是脚本语言? ①脚本语言介于HTML和C,C++,Java,C#等编程语言之间 ②脚本语言与编程语言有相似地方,其函数与编程语言类似,也有变量.与编程语言之间最大的区别是编程语言的语法和规则更为严 ...
- [笔记]原生JS实现的DOM操作笔记
原生JS实现的DOM一系列操作参考: 原生JavaScript封装DOM库 siblings: 原生JS-查找相邻的元素-siblings方法的实现 addClass,removeClass,hasC ...
- 一文看懂HTTPS的核心知识
1.HTTPS历史 由于HTTP的消息传输的安全隐患,于是网景公司在1994年设计了SSL(Secure Sockets Layer,安全套接字层)协议,目的是保障网上交易安全,从而就诞生了HTTPS ...
- MyEclipse自动补全
打开MyEclipse 6.5,然后"window"→"Preferences". 选择"java",展开,"Editor&quo ...
- 使用代码检查Dynamics 365中的备用键状态
摘要: 微软动态CRM专家罗勇 ,回复304或者20190213可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 备用键(Al ...
- arcgis api 3.x for js 入门开发系列十叠加 SHP 图层(附源码下载)
前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...
- Azure WebJob-Custom Schedule for Azure Web Job Timer Triggers
如果想实现Azure Schedule WebJob,有两种方法: 1. 配置CRON Expression,网上有在线CRON配置工具,根据业务需要配置即可 注意:Azure的CRON Expres ...
- OpenUDID 和 IDFA 比较
iOS标识符 现今来比较下,不同情况下两种标识符的变化情况.以下试验,每种标识符均分为存于Keychain和未存于Keychain的两种情况做比较. 广告标识符(IDFA-identifierForI ...
- C# 类如何声明索引器以提供对类的类似数组的访问的代码
研发期间,将内容过程中比较常用的内容段做个收藏,如下内容内容是关于 C# 类如何声明索引器以提供对类的类似数组的访问.的内容,希望能对各位有用处. using System;using System. ...
- Netty学习笔记(五) 使用Netty构建静态网页服务器
昨天在继续完善基于Netty构建的聊天室系统的过程中,发现了一个有意思的知识点,特此拿来做一个简单的静态网页服务器,好好的玩一玩Netty. 但是不管怎么说利用netty实现各种功能的流程都是类似的 ...