LCA + 树状数组 + 树上RMQ
题目链接:http://poj.org/problem?id=2763
思路:首先求出树上dfs序列,并且标记树上每个节点开始遍历以及最后回溯遍历到的时间戳,由于需要修改树上的某两个节点之间的权值,如果parent[v] = u, 那么说明修改之后的v的子树到当前根的距离都会改变,由于遍历到v时有开始时间戳以及结束时间戳,那么处于这个区间所有节点都会影响到,于是我们可以通过数组数组来更新某个区间的值,只需令从区间起始点之后的每个值都增加一个改变量了,令区间中止点之后的每个值都减小一个改变量,这样我们就可以得到处于该区间的值的改变量。至于如何求树上两个节点的LCA,这里可以使用RMQ,O(n
* log(n))的预处理,O(1)的查询复杂度。\
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std; const int MAX_N = (200000 + 10000);
struct Edge {
int u, v, w, next;
Edge () {}
Edge (int _u, int _v, int _w, int _next) : u(_u), v(_v), w(_w), next(_next) {}
} EE[MAX_N << 2], edge[MAX_N << 2]; int NE, head[MAX_N];
void Init()
{
NE = 0;
memset(head, -1, sizeof(head));
} void Insert(int u, int v, int w)
{
edge[NE].u = u;
edge[NE].v = v;
edge[NE].w = w;
edge[NE].next = head[u];
head[u] = NE++;
} int index, dfs_seq[MAX_N << 2]; //dfs序列
int First[MAX_N], End[MAX_N]; //First数组表示第一次遍历到的时间戳,End数组表示最后回溯时遍历到的时间戳
int parent[MAX_N], dep[MAX_N << 2]; //深度
int N, Q, st, cost[MAX_N]; void dfs(int u, int fa, int d, int c)
{
parent[u] = fa;
First[u] = index;
dfs_seq[index] = u;
dep[index++] = d;
cost[u] = c; for (int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].v, w = edge[i].w;
if (v == fa) continue;
dfs(v, u, d + 1, cost[u] + w);
dfs_seq[index] = u;
dep[index++] = d;
} End[u] = index;
} int dp[MAX_N][40]; //dp[i][j]表示从时间戳i开始,长度为(1 << j)的区间中深度最小的点的时间戳
void Init_RMQ()
{
for (int i = 0; i < index; ++i) dp[i][0] = i;
for (int j = 1; (1 << j) < index; ++j) {
for (int i = 0; i + (1 << j) - 1 < index; ++i) {
dp[i][j] = (dep[ dp[i][j - 1] ] < dep[ dp[i + (1 << (j - 1))][j - 1] ] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1]);
}
}
} int RMQ_Query(int l, int r)
{
int k = (int)(log(r * 1.0 - l + 1) / log(2.0));
return (dep[ dp[l][k] ] < dep[ dp[r - (1 << k) + 1][k] ] ? dp[l][k] : dp[r - (1 << k) + 1][k]);
} int LCA(int x, int y)
{
if (x > y) swap(x, y);
return dfs_seq[RMQ_Query(x, y)];
} int C[MAX_N << 2];
int lowbit(int x)
{
return x & (-x);
}
void update(int i, int val)
{
while (i < index) {
C[i] += val;
i += lowbit(i);
}
} int getSum(int i)
{
int sum = 0;
while (i > 0) {
sum += C[i];
i -= lowbit(i);
}
return sum;
} int main()
{
while (~scanf("%d %d %d", &N, &Q, &st)) {
Init();
for (int i = 1; i < N; ++i) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
Insert(u, v, w);
Insert(v, u, w);
EE[i] = Edge(u, v, w, -1);
} index = 0;
dfs(st, st, 0, 0); Init_RMQ(); memset(C, 0, sizeof(C));
for (int i = 1; i <= Q; ++i) {
int opt;
scanf("%d", &opt);
if (opt == 0) {
int ed, fa, x, y, z;
scanf("%d", &ed);
x = First[st], y = First[ed], z = First[fa = LCA(x, y)];
printf("%d\n", getSum(x + 1) + getSum(y + 1) - 2 * getSum(z + 1) + cost[st] + cost[ed] - 2 * cost[fa]);
st = ed; } else {
int id, w;
scanf("%d %d", &id, &w);
int u = EE[id].u, v = EE[id].v, tmp = w - EE[id].w;
EE[id].w = w; if (parent[u] == v) swap(u, v);
update(First[v] + 1, tmp);
update(End[v] + 1, -tmp);
}
}
}
return 0;
}
LCA + 树状数组 + 树上RMQ的更多相关文章
- hdu 6203 ping ping ping(LCA+树状数组)
hdu 6203 ping ping ping(LCA+树状数组) 题意:给一棵树,有m条路径,问至少删除多少个点使得这些路径都不连通 \(1 <= n <= 1e4\) \(1 < ...
- HDU 6203 ping ping ping(dfs序+LCA+树状数组)
http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连 ...
- POJ 2763 Housewife Wind(DFS序+LCA+树状数组)
Housewife Wind Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 11419 Accepted: 3140 D ...
- BZOJ 4999: This Problem Is Too Simple! DFS序+LCA+树状数组+离线
Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) , ...
- 求解区间问题的三种做法的区别 线段树、树状数组、RMQ
树状数组主要用于计算区间的和,在区间元素修改值的时候能够快速修改而不是以O(n)的复杂度进行修改: 线段树是把区间以树的形式分拆为若干个小区间,每个小区间存的都有一个值(树状数组的元素存的是区间值), ...
- HDU 3966 dfs序+LCA+树状数组
题目意思很明白: 给你一棵有n个节点的树,对树有下列操作: I c1 c2 k 意思是把从c1节点到c2节点路径上的点权值加上k D c1 c2 k 意思是把从c1节点到c2节点路径上的点权值减去k ...
- 蓝书4.1-4.4 树状数组、RMQ问题、线段树、倍增求LCA
这章的数据结构题很真实 T1 排队 bzoj 1699 题目大意: 求静态一些区间的最大值-最小值 思路: ST表裸题 #include<iostream> #include<cst ...
- LCA+树状数组 POJ 2763 Housewife Wind
题目传送门 题意:两种操作,问u到v的距离,并且u走到了v:把第i条边距离改成w 分析:根据DFS访问顺序,将树处理成链状的,那么回边处理成负权值,那么LCA加上BIT能够知道u到v的距离,BIT存储 ...
- HDU 5296 Annoying problem LCA+树状数组
题解链接 Annoying problem Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/O ...
随机推荐
- c# 备份数据库恢复数据库
/// <summary> /// 对数据库的备份和恢复操作,Sql语句实现 /// </summary> /// <param name="cmdText&q ...
- hihoCoder 后缀自动机三·重复旋律6
后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...
- 关于背景图相对父容器垂直居中问题 —— vertical-align 和 line-height 之间的区别
html css <div class="register-wrapper"> <div class="register"> &l ...
- mysql索引失效
在做项目的过程中,难免会遇到明明给mysql建立了索引,可是查询还是很缓慢的情况出现,下面我们来具体分析下这种情况出现的原因及解决方法 索引并不是时时都会生效的,比如以下几种情况,将导致索引失效: ...
- 文件夹锁定(Source)
文件夹锁定(Source)private void Lock(string folderPath){ try { string adminUserName = Environ ...
- SSH Junit4测试
package test; import static org.junit.Assert.*; import java.util.List; import org.hibernate.SessionF ...
- Phabricator是什么,代码审查工具
Phabricator是什么? Phabricator支持两种代码审查工作流:"review"(提交前审查)和 "audit"(提交后审查). Phabrica ...
- util类中非静态方法中注入serivce,在controller层是使用util。
今天碰到如题的问题,刚一开始在util中注入service总是注入失败,起初我以为是util中没有注入成功,debug看了一下果然注入不进来. 然后各种纠结,最终坑爹的问题是在controller直接 ...
- codevs3250 操作序列
题目描述 Description Petya是一个非常好玩孩子.他很无聊,因此他开始玩下面的游戏: 他得到一个长度为N的整数序列,他会对这些数字进行操作,他可以把某个数的数值加1或者减1(当然他可以对 ...
- 代理模式及jdk动态代理原理
代理模式 :为其它对象提供代理,以控制对这个对象的访问. 代理模式的特征:代理类(proxyClass)与委托类(realClass)有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转 ...