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 ...
随机推荐
- css-display:none和visibility:hidden的不同
摘自张鑫旭老师的博客-- display:none和visibility:hidden都能使元素隐藏,但是有明显区别,主要有以下三点: 空间占据 重排与重绘 株连性 1.空间占据. 使用display ...
- Leetcode 230. Kth Smallest Element in a BST
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Not ...
- signalr-源码
1.一对一聊天 2.多对多 3.离线消息 1)群聊离线 2.1对一聊天离线 源码地址:https://github.com/aa1356889/SignalrCode 操作步骤 部署网站到iis 网上 ...
- COGS746. [网络流24题] 骑士共存
骑士共存问题«问题描述:在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示.棋盘 上某些方格设置了障碍,骑士不得进入. «编程任务:对于给定的n*n个方格的国际象棋棋盘和障碍标志 ...
- 在WildFly中运行多个standalone模式的实例
WildFly作为一款优秀的EJB容器,其前身为JBoss AS.JBoss作为一款开源的应用服务器,被广泛的应用在各种项目当中.假设我们现在有这样一个项目,他是以standalone的模式运行在 ...
- sql 的实用函数(包含日期函数、截取字符串函数)
CONVERT() 函数是把日期转换为新数据类型的通用函数. CONVERT() 函数可以用不同的格式显示日期/时间数据. 语法 CONVERT(data_type(length),data_to_b ...
- .Net 中的反射(查看基本类型信息) - Part.2
反射概述 和Type类 1.反射的作用 简单来说,反射提供这样几个能力:1.查看和遍历类型(及其成员)的基本信息和程序集元数据(metadata):2.迟绑定(Late-Binding)方法和属性.3 ...
- 深入C#内存管理来分析值类型&引用类型,装箱&拆箱,堆栈几个概念组合之间的区别
C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程 ...
- GPS模块数据放入谷歌地图显示,不准
GPS 串口读出的是 DDMM.MMMM格式 一般上位机是 DD.DDDDDD°或 DD°MM'SS" 格式, 这两种都可以在 GE 里直接输入 举例说明: 3147.8749 (示例,经纬 ...
- Android-修改TabWidget字体大小颜色及对齐
在Android中,我们可以定义TabWidget来分页.在上一篇文章中有说到使用TabWidget定义Tab分页布局,但大部分用户可能会觉得默认的字体有点小,但Tab选项卡默认又不能设定字体大小,如 ...