HDU 3966 基础树链剖分
题意:给一棵树,并给定各个点权的值,然后有3种操作:
I C1 C2 K: 把C1与C2的路径上的所有点权值加上K
D C1 C2 K:把C1与C2的路径上的所有点权值减去K
Q C:查询节点编号为C的权值
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 50010
#define ls o<<1
#define rs o<<1|1
#define define_m int m=(l+r)>>1
#define ll long long
int n , m , q , first[N] , k; struct Edge{
int y , next;
Edge(){}
Edge(int y , int next):y(y),next(next){}
}e[N<<]; void add_edge(int x , int y)
{
e[k] = Edge(y , first[x]);
first[x] = k++;
} int sz[N] , fa[N] , son[N] , top[N] , dep[N] , id[N] , number;
void dfs(int u , int f , int d)
{
fa[u] = f;
sz[u] = , dep[u] = d , son[u] =;
int maxn = ;
for(int i=first[u] ; ~i ; i=e[i].next){
int v= e[i].y;
if(v == f) continue;
dfs(v , u , d+);
sz[u] += sz[v];
if(sz[v]>maxn) son[u] = v , maxn=sz[v];
}
} void dfs1(int u , int f , int head)
{
top[u] = head;
if(son[u]){
id[son[u]] = ++number;
dfs1(son[u] , u , head);
}
for(int i=first[u] ; ~i ; i=e[i].next){
int v = e[i].y;
if(v == f || v == son[u]) continue;
id[v] = ++number;
dfs1(v , u , v);
}
} int val[N] , add[N<<] , siz[N<<];
ll sum[N<<]; void push_up(int o){sum[o] = sum[ls]+sum[rs];} void push_down(int o)
{
if(add[o]){
add[ls] += add[o] , add[rs] += add[o];
sum[ls] += (ll)add[o]*siz[ls] , sum[rs] += (ll)add[o]*siz[rs];
add[o] = ;
}
} void build(int o , int l , int r)
{
add[o] = , siz[o] = r-l+;
if(l==r){
sum[o] = (ll)val[l];
return ;
}
define_m;
build(ls , l , m);
build(rs , m+ , r);
push_up(o);
} void update(int o , int l , int r , int s , int t , int v)
{
if(l>=s && r<=t){
sum[o] += (ll)siz[o]*v;
add[o] += v;
return ;
}
define_m;
push_down(o);
if(m>=s) update(ls , l , m , s , t , v);
if(m<t) update(rs , m+ , r , s , t , v);
push_up(o);
} ll query(int o , int l , int r , int p)
{
if(l==r && l==p) return sum[o];
push_down(o);
define_m;
if(m>=p) return query(ls , l , m, p);
else return query(rs , m+ , r , p);
} void updatePath(int u , int v , int change)
{
int top1 = top[u] , top2 = top[v];
while(top1!=top2){
if(dep[top1]<dep[top2]){
swap(top1 , top2);
swap(u , v);
}
update( , , n , id[top1] , id[u] , change);
u = fa[top1];
top1 = top[u];
} if(dep[u]<dep[v]) swap(u , v);
update( , , n , id[v] , id[u] , change); } char str[]; int main()
{
// freopen("in.txt" , "r" , stdin);
while(~scanf("%d%d%d" ,&n , &m , &q))
{
for(int i= ; i<=n ; i++) scanf("%d" , val+i);
memset(first , - , sizeof(first));
k = ;
while(m--){
int u , v;
scanf("%d%d" , &u , &v);
add_edge(u,v);
add_edge(v,u);
}
number = ;
dfs( , , );
id[] = ++number;
dfs1( , , );
// for(int i=1 ; i<=n ; i++) cout<<i<<" "<<son[i]<<" "<<id[i]<<endl;
int tmp[N];
for(int i= ; i<=n ; i++) tmp[i]=val[i];
for(int i= ; i<=n ; i++) val[id[i]] = tmp[i];
build( , , n);
for(int i= ; i<q ; i++){
int s , t , v;
scanf("%s" , str);
if(str[] == 'Q'){
scanf("%d" , &v);
ll ans = query( , , n , id[v]);
printf("%d\n" , (int)ans);
}else if(str[]=='I'){
scanf("%d%d%d" , &s , &t , &v);
updatePath(s , t , v);
}else{
scanf("%d%d%d" , &s , &t , &v);
updatePath(s , t , -v);
}
}
}
return ;
}
HDU 3966 基础树链剖分的更多相关文章
- HDU 3966(树链剖分+点修改+点查询)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题目大意:营地的分布成树型.每个营地都有一些人,每次修改修改一条链上的所有营地的人数,每次查询单 ...
- HDU 3966 RE 树链剖分 线段树 Aragorn's Story
题意: 给出一棵树,每个顶点上有一个权值. 操作:选择一条路径,并将路径上所有的点的权值同时加或减某个数. 查询:某个点的当前权值 分析: 树链剖分完毕后,就是简单的线段树区间更新. 提交的时候注意要 ...
- hdu 5458 Stability(树链剖分+并查集)
Stability Time Limit: 3000/2000 MS (Java/Others) Memory Limit: 65535/102400 K (Java/Others)Total ...
- HDU 5044 (树链剖分+树状数组+点/边改查)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变 ...
- HDU 5458 Stability (树链剖分+并查集+set)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5458 给你n个点,m条边,q个操作,操作1是删边,操作2是问u到v之间的割边有多少条. 这题要倒着做才 ...
- HDU 5044 Tree --树链剖分
题意:给一棵树,两种操作: ADD1: 给u-v路径上所有点加上值k, ADD2:给u-v路径上所有边加上k,初始值都为0,问最后每个点和每条边的值,输出. 解法:树链剖分可做,剖出来如果直接用线段树 ...
- HDU - 3966-Aragorn' Story(树链剖分+线段树)
链接:https://vjudge.net/problem/HDU-3966 题意: Our protagonist is the handsome human prince Aragorn come ...
- HDU 5242 利用树链剖分思想进行贪心
题目大意: 在给定带权值节点的树上从1开始不回头走到某个底端点后得到所有经过的点的权值后,这些点权值修改为0,到达底部后重新回到1,继续走,问走k次,最多能得到多少权值之和 这其实就是相当于每一次都走 ...
- Tree HDU - 6547 (树链剖分,线段树)
wls 有三棵树,树上每个节点都有一个值 ai,现在有 2 种操作: 将一条链上的所有节点的值开根号向下取整: 求一条链上值的和: 链的定义是两点之间的最短路. Input 第一行两个数 n, q 分 ...
随机推荐
- Android 面试题总结
Android 面试题总结(不断更新) 1.INETNT几种有关Activit的启动方式FLAG_ACTIVITY_BROUGHT_TO_FRONT 将ACTIVITY带到最前面FLAG_ACTIVI ...
- PHP SPL标准库之SplFixedArray使用实例
SplFixedArray主要是处理数组相关的主要功能,与普通php array不同的是,它是固定长度的,且以数字为键名的数组,优势就是比普通的数组处理更快. 看看我本机的Benchmark测试: i ...
- java读取properties配置文件的方法
app.properties mail.smtp.host=smtp.163.com mail.transport.protocol=smtp import java.io.InputStream; ...
- vi编辑器简单应用(摘抄)
摘抄于 vi编辑器的使用 (2) (3) 1 vi编辑器的基本使用 1.1 vi的启动 打开: $ vi example.c 只读打开 $ vi –R example.c 1.2 vi的工作模式 1. ...
- nginx安装笔记
双节点安装 1 节点一 1.1 目录 /usr/local cd /usr/local 1.2 openssl rpm -ql openssl /usr/share/doc/openssl-1.0.0 ...
- javascript算术运算符详解
算术运算符 +.-.*./.%.++.-- ++.--分为前缀形式和后缀形式 前缀形式先加减1在执行 后缀形式先执行再加减1 注意 +号用来连接两个字符串 只要+连接的操作数中有一个是字符串型,JS就 ...
- requestAnimationFrame兼容性扩展
/** * requestAnimationFrame兼容性扩展,两方面工作: * 1.把各浏览器前缀进行统一 * 2.在浏览器没有requestAnimationFrame方法时将其指向setTim ...
- 日期操作类--SimpleDateFormat类
使用SimpleDateFormat格式化日期 SimpleDateFormat是一个以语言环境敏感的方式来格式化和分析日期的类.SimpleDateFormat允许你选择任何用户自定义日期时间格式来 ...
- 指针类型(C# 编程指南)
原文地址:https://msdn.microsoft.com/zh-cn/library/y31yhkeb.aspx 在不安全的上下文中,类型可以是指针类型.值类型或引用类型. 指针类型声明采用下列 ...
- 面试时,问哪些问题能试出一个 Android 应用开发者真正的水平?【转自知乎】
这几年面过的各种Android开发也有三位数了,failed的不敢说,pass的基本都没有看走眼,来得晚了也想说说我的体会. 一般面试时间短则30分钟,多则1个小时,这么点时间要全面考察一个人难度很大 ...