Description

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
Input

第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
Output

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

Sample Input

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
Sample Output

6

9

13

HINT

对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

题解:很裸的树剖题了……然而竟然因为写错了线段树调了一个多小时……emmm,如果分块是O(nlogn)的就好了┑( ̄Д  ̄)┍

代码如下:

#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lson root<<1
#define rson root<<1|1
#define hi puts("hi");
using namespace std; struct node
{
long long l,r,lazy,sum;
} tr[];
long long deep[],fa[],size[],son[],id[],top[],w[],c[],cnt=;
vector<int> g[]; void push_up(int root)
{
tr[root].sum=tr[lson].sum+tr[rson].sum;
} void push_down(int root)
{
int mid=(tr[root].l+tr[root].r)>>;
tr[lson].sum+=(mid-tr[root].l+)*tr[root].lazy;
tr[lson].lazy+=tr[root].lazy;
tr[rson].sum+=(tr[root].r-mid)*tr[root].lazy;
tr[rson].lazy+=tr[root].lazy;
tr[root].lazy=;
} void build(int root,int l,int r)
{
if(l==r)
{
tr[root].l=l;
tr[root].r=r;
tr[root].sum=w[l];
return ;
}
tr[root].l=l;
tr[root].r=r;
int mid=(l+r)>>;
build(lson,l,mid);
build(rson,mid+,r);
push_up(root);
} void add(int root,int l,int r,int x)
{
if(l==tr[root].l&&r==tr[root].r)
{
tr[root].lazy+=x;
tr[root].sum+=(tr[root].r-tr[root].l+)*x;
return;
}
int mid=(tr[root].l+tr[root].r)>>;
if(tr[root].lazy) //
{
push_down(root);
}
if(l>mid)
{
add(rson,l,r,x); //!!!
}
else
{
if(r<=mid)
{
add(lson,l,r,x); //!!!
}
else
{
add(lson,l,mid,x);
add(rson,mid+,r,x);
}
}
push_up(root); //
} long long query(int root,int l,int r)
{
if(l==tr[root].l&&tr[root].r==r)
{
return tr[root].sum;
}
int mid=(tr[root].l+tr[root].r)>>;
if(tr[root].lazy)
{
push_down(root); //
}
if(l>mid)
{
return query(rson,l,r); //!!!
}
else
{
if(r<=mid)
{
return query(lson,l,r); //!!!
}
}
return query(lson,l,mid)+query(rson,mid+,r);
} void dfs1(int now,int f,int dep)
{
deep[now]=dep;
fa[now]=f;
size[now]=;
int maxson=-;
for(int i=;i<g[now].size();i++)
{
if(g[now][i]==f)
{
continue;
}
dfs1(g[now][i],now,dep+);
size[now]+=size[g[now][i]]; //
if(size[g[now][i]]>maxson)
{
son[now]=g[now][i];
maxson=size[g[now][i]];
}
}
} void dfs2(int now,int topf)
{
id[now]=++cnt;
w[cnt]=c[now];
top[now]=topf;
if(!son[now])
{
return ;
}
dfs2(son[now],topf);
for(int i=;i<g[now].size();i++)
{
if(g[now][i]==son[now]||g[now][i]==fa[now])
{
continue;
}
dfs2(g[now][i],g[now][i]);
}
} void point_add(int x,int val)
{
add(,id[x],id[x],val);
} void sub_add(int x,int val)
{
add(,id[x],id[x]+size[x]-,val);
} void path_sum(int x,int y)
{
long long ans=;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) //
{
swap(x,y);
}
ans+=query(,id[top[x]],id[x]);
x=fa[top[x]];
}
if(deep[x]>deep[y])
{
swap(x,y);
}
ans+=query(,id[x],id[y]);
printf("%lld\n",ans);
} int main()
{
int n,m,kd,x,a;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%lld",&c[i]);
}
for(int i=;i<=n-;i++)
{
int from,to;
scanf("%d%d",&from,&to);
g[from].push_back(to);
g[to].push_back(from);
}
dfs1(,,);
dfs2(,);
build(,,n);
for(int i=;i<=m;i++)
{
scanf("%d",&kd);
if(kd==)
{
scanf("%d%d",&x,&a);
point_add(x,a);
}
if(kd==)
{
scanf("%d%d",&x,&a);
sub_add(x,a);
}
if(kd==)
{
scanf("%d",&x);
path_sum(,x);
}
}
}

省选一试爆炸了qwq

BZOJ 4034[HAOI2015]树上操作(树链剖分)的更多相关文章

  1. bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 4352  Solved: 1387[Submit][Stat ...

  2. bzoj 4034: [HAOI2015]树上操作——树链剖分

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

  3. bzoj4034[HAOI2015]树上操作 树链剖分+线段树

    4034: [HAOI2015]树上操作 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 6163  Solved: 2025[Submit][Stat ...

  4. bzoj 4034 [HAOI2015] T2(树链剖分,线段树)

    4034: [HAOI2015]T2 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1536  Solved: 508[Submit][Status] ...

  5. BZOJ 4034 [HAOI2015]T2(树链剖分)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4034 [题目大意] 有一棵点数为 N 的树,以点 1 为根,且树点有边权. 有 M 个 ...

  6. 【BZOJ4034】[HAOI2015]树上操作 树链剖分+线段树

    [BZOJ4034][HAOI2015]树上操作 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 ...

  7. BZOJ4034 [HAOI2015]树上操作 树链剖分

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ4034 题意概括 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三 ...

  8. P3178 [HAOI2015]树上操作 树链剖分

    这个题就是一道树链剖分的裸题,但是需要有一个魔性操作___编号数组需要开longlong!!!震惊!真的神奇. 题干: 题目描述 有一棵点数为 N 的树,以点 为根,且树点有边权.然后有 M 个操作, ...

  9. BZOJ4034[HAOI2015]树上操作——树链剖分+线段树

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

随机推荐

  1. Android Theme的使用

    原文地址 http://www.cnblogs.com/Dentist/p/4369816.html Theme是一套UI控件和Activity的样式.可以给Application 和 activit ...

  2. distinct与order by

    不知为啥,当我得查询中出现distinct时,order by 中必须包含要查询的列,否则报错. SELECT DISTINCT a.DetailId, a.OrderId, a.ProductId, ...

  3. 阿里云ubuntu12.04环境下配置Apache+PHP+PHPmyadmin+MYsql

    此教程中使用的相关IP等设置,在你的环境中要做相应修改. 使用之前更新apt-get,因为服务器基本上是一个裸系统 apt-get update;apt-get upgrade; 1 我们使用root ...

  4. java代码多线程实现如下

    总结:我的比赛得了最差的奖,老师提都没提,所以,我应该有自知之明,你并不是他最喜欢的学生 import java.util.Scanner; //利用多线程实现输入等待…… public class ...

  5. 求分数1+1/2+1/3+.....+1/n的值

    总结:自己理解错了的有以下几点: 1.s初始化的值是0.但数据类型最好定位double双精度类型 2.for循环里面的i<n.不要忘了等号,因为i作为分母,不能为0,所以从1开始, 3.在mai ...

  6. Java-Maven-Runoob:Maven教程

    ylbtech-Java-Maven-Runoob:Maven教程 1.返回顶部 1. Maven 教程 Maven 翻译为"专家"."内行",是 Apache ...

  7. 支付宝pc端支付接入PHP实现

    引入支付宝接口 放入一个插件库中,方便管理 创建支付类 1.发起支付 public function init() { $order_id = $_REQUEST['order_id']; $orde ...

  8. python学习(一) 基础知识

    开始学习<Python基础教程> 1.2 交互式解释器 按照书上的例子敲了个最简单的print函数,居然报错: >>> print "fsdfs"Sy ...

  9. Linux - 文件合并

    >:左边命令的结果覆盖右边文件的内容 cat 命令,把文件的内容覆盖另一个文件中的内容 把两个文件的内容合并到一个文件中 echo 命令 whoami 命令 >>:把左边命令执行的结 ...

  10. Python多线程-守护线程

    守护线程:守护着非守护线程,守护线程和非守护线程同时运行,当非守护线程运行结束后,无论守护线程有没有运行完,脚本都会停止运行 首先看一段普通的多线程实例 # -*- coding:utf-8 -*- ...