hdu 3966 Aragorn's Story(树链剖分+区间修改+单点查询)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966
题意:给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值
题解:就是树链剖分具体看代码,还有注释。
#include <iostream>
#include <cstring>
using namespace std;
const int M = 5e4 + 10;
struct Edge {
int v , next , w;
}edge[M << 1];
int head[M] , e;//链式前向星存边
int top[M];//重链的根节点
int fa[M];//fa[i]表示i的父节点
int deep[M];//节点的深度
int num[M];//num[i]表示i节点子树一共有多少节点
int p[M];//p[i]表示i点在线段树中的位置
int fp[M];//fp[i]表示线段树中位置为i的节点是什么
int son[M];//sum[u]表示u点的重儿子
int pos;
void init() {
memset(head , -1 , sizeof(head));
memset(son , -1 , sizeof(son));
e = 0;
pos = 1;
}//初始化
void add(int u , int v) {
edge[e].v = v;
edge[e].next = head[u];
head[u] = e++;
}//加边
void dfs1(int u , int pre , int d) {
deep[u] = d;
fa[u] = pre;
num[u] = 1;
for(int i = head[u] ; i != -1 ; i = edge[i].next) {
int v = edge[i].v;
if(v != pre) {
dfs1(v , u , d + 1);
num[u] += num[v];
if(son[u] == -1 || num[v] > num[son[u]]) {
son[u] = v;
}
}
}
}//寻找重点
void getpos(int u , int sp) {
top[u] = sp;
p[u] = pos++;
fp[pos - 1] = u;
if(son[u] == -1)
return ;
getpos(son[u] , sp);
for(int i = head[u] ; i != -1 ; i = edge[i].next) {
int v = edge[i].v;
if(v != son[u] && v != fa[u]) {
getpos(v , v);
}
}
}//构建重链
struct TnT {
int l , r , sum , lazy;
}T[M << 2];
int a[M];
void build(int l , int r , int i) {
int mid = (l + r) >> 1;
T[i].l = l , T[i].r = r , T[i].lazy = 0 , T[i].sum = 0;
if(T[i].l == T[i].r) {
T[i].sum = a[fp[l]];
return ;
}
build(l , mid , i << 1);
build(mid + 1 , r , (i << 1) | 1);
T[i].sum = T[i << 1].sum + T[(i << 1) | 1].sum;
}
void pushdown(int i) {
if(T[i].lazy) {
T[i << 1].sum += T[i].lazy * (T[i << 1].r - T[i << 1].l + 1);
T[(i << 1) | 1].sum += T[i].lazy * (T[(i << 1) | 1].r - T[(i << 1) | 1].l + 1);
T[i << 1].lazy += T[i].lazy;
T[(i << 1) | 1].lazy += T[i].lazy;
T[i].lazy = 0;
}
}
void updata(int l , int r , int ad , int i) {
int mid = (T[i].l + T[i].r) >> 1;
if(T[i].l == l && T[i].r == r) {
T[i].sum += ad * (r - l + 1);
T[i].lazy += ad;
return ;
}
pushdown(i);
if(mid < l) {
updata(l , r , ad , (i << 1) | 1);
}
else if(mid >= r) {
updata(l , r , ad , i << 1);
}
else {
updata(l , mid , ad , i << 1) , updata(mid + 1 , r , ad , (i << 1) | 1);
}
T[i].sum = T[i << 1].sum + T[(i << 1) | 1].sum;
}
int query(int i , int pos) {
int mid = (T[i].l + T[i].r) >> 1;
if(T[i].l == pos && T[i].r == pos) {
return T[i].sum;
}
pushdown(i);
T[i].sum = T[i << 1].sum + T[(i << 1) | 1].sum;
if(mid < pos) {
return query((i << 1) | 1 , pos);
}
else {
return query(i << 1 , pos);
}
}
void change(int u , int v , int ad) {
int f1 = top[u] , f2 = top[v];
while(f1 != f2) {
if(deep[f1] < deep[f2]) {
swap(f1 , f2);
swap(u , v);
}
updata(p[f1] , p[u] , ad , 1);
u = fa[f1] , f1 = top[u];
}
if(deep[u] < deep[v])
swap(u , v);
updata(p[v] , p[u] , ad , 1);
}//树链剖分特别的更新方法,类似于lca从各子链上查询直到到了同一条重链上自行理解一下。
int main() {
int n , m , q , x , y , z;
while(scanf("%d%d%d" , &n , &m , &q) != EOF) {
init();
for(int i = 1 ; i <= n ; i++) {
scanf("%d" , &a[i]);
}
for(int i = 0 ; i < m ; i++) {
scanf("%d%d" , &x , &y);
add(x , y);
add(y , x);
}
dfs1(1 , 0 , 0);
getpos(1 , 1);
char cp[5];
build(0 , pos + 1 , 1);
while(q--) {
scanf("%s" , cp);
if(cp[0] == 'I') {
scanf("%d%d%d" , &x , &y , &z);
change(x , y , z);
}
if(cp[0] == 'D') {
scanf("%d%d%d" , &x , &y , &z);
change(x , y , -z);
}
if(cp[0] == 'Q') {
scanf("%d" , &x);
printf("%d\n" , query(1 , p[x]));
}
}
}
return 0;
}
hdu 3966 Aragorn's Story(树链剖分+区间修改+单点查询)的更多相关文章
- HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树
HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...
- Hdu 3966 Aragorn's Story (树链剖分 + 线段树区间更新)
题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2 ...
- HDU 3966 Aragorn's Story(树链剖分)(线段树区间修改)
Aragorn's Story Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- HDU 3966 Aragorn's Story 树链剖分+BIT区间修改/单点询问
Aragorn's Story Description Our protagonist is the handsome human prince Aragorn comes from The Lord ...
- HDU 3966 Aragorn's Story (树链剖分入门题)
树上路径区间更新,单点查询. 线段树和树状数组都可以用于本题的维护. 线段树: #include<cstdio> #include<iostream> #include< ...
- HDU 3966 Aragorn's Story 树链剖分
Link: http://acm.hdu.edu.cn/showproblem.php?pid=3966 这题注意要手动扩栈. 这题我交g++无限RE,即使手动扩栈了,但交C++就过了. #pragm ...
- hdu 3966 Aragorn's Story : 树链剖分 O(nlogn)建树 O((logn)²)修改与查询
/** problem: http://acm.hdu.edu.cn/showproblem.php?pid=3966 裸板 **/ #include<stdio.h> #include& ...
- hdu 3966 Aragorn's Story 树链剖分 按点
Aragorn's Story Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 【树状数组区间修改单点查询+分组】HDU 4267 A Simple Problem with Integers
http://acm.hdu.edu.cn/showproblem.php?pid=4267 [思路] 树状数组的区间修改:在区间[a, b]内更新+x就在a的位置+x. 然后在b+1的位置-x 树状 ...
随机推荐
- SCI论文的时态
如果有的杂志对时态有要求,则以下所述都没有用了. 有些杂志也会专门有些比较“特别”的要求,比如Cell,要求Abstract全部使用一般现在时. 英语谓语动词时态共有16种,在英文科技论文中用得较为频 ...
- Thinkphp5.0快速入门笔记(2)
学习来源与说明 https://www.kancloud.cn/thinkphp/thinkphp5_quickstart 测试与部署均在windows10下进行学习. 示例建立新的模块和控制器 在a ...
- 初识代理——Proxy
无处不在的模式——Proxy 最近在看<设计模式之禅>,看到代理模式这一章的时候,发现自己在写spring项目的时候其实很多时候都用到了代理,无论是依赖注入.AOP还是其他,可以说是无处不 ...
- 3、数组的声明及初始化(test1.java)
今天学习了,一位数组和二维数组,先学习了数组的申请,数组的初始化,数组的拷贝等.对于数组我认为,和C\C++中的数组,没有什么太大的区别,但是在JAVA中,大家都知道JAVA是面向对象的编程语言,每一 ...
- Java中只有值传递,(及值传递与引用传递详解)
首先呢,我们来说一下值传递与引用传递的区别(这两个玩意儿实在调用函数的时候提到的) 比如说 code( a) code( int a ) code(a)是调用函数,a是我们原本函数的一个值类型,然后使 ...
- hadoop学习(四)----windows环境下安装hadoop
因为我们不能在线上环境进行调试hadoop,这样就只能在本地先调试好了再放到线上去啦.我本地是windows环境,今天先记下windows下搭建hadoop2.7的步骤. 1 本地环境 windows ...
- manifest.json 解析--手机web app开发笔记(三-2)
四.SDK配置和模块权限配置 SDK 就是 Software Development Kit 的缩写,中文意思就是“软件开发工具包”,也就是辅助开发某一类软件的相关文档.范例和工具的集合都可以叫做“S ...
- Mysql 局域网连接设置——Windows
在公司工作中,会遇到mysql数据库存储于某个人的电脑上,大家要想连接mysql服务,装有mysql服务的电脑就必须开启远程连接. 其实不仅仅是局域网,只要你有数据库所在服务器的公网IP地址都能连上. ...
- ASP.NET Core 框架本质学习
本文作为学习过程中的一个记录. 学习文章地址: https://www.cnblogs.com/artech/p/inside-asp-net-core-framework.html 一. ASP.N ...
- C++ “::” 作用域符 双冒号
C++ "::" 作用域符 双冒号 作用域符 :: 是作用域符,是运算符中等级最高的,它分为三种: 1)global scope(全局作用域符),用法(::name) 2)clas ...