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 ...
随机推荐
- Alpha阶段第八次Scrum Meeting
情况简述 Alpha阶段第八次Scrum Meeting 敏捷开发起始时间 2016/10/31 00:00 敏捷开发终止时间 2016/10/32 00:00 会议基本内容摘要 跟助教进行了交流,明 ...
- java如何跳出多重嵌套循环
Java里的break能跳出循环但是只能跳出一个,goto这个在java中也只是被当作关键是,没有任何作用 要做到跳出多重嵌套循环,可以用此方法 在循环体开头设置一个标志位,设置一个标记,然后使用带此 ...
- <<< Jquery查找元素、选择器使用方法总结
$("#myDiv"); //根据给定的ID匹配一个元素,用于搜索id 属性中给定的值,id属性必须是唯一的 $("div"); //根据给定的元素名匹配所有元 ...
- PHP文件大小格式化函数合集
比如碰到一个很大的文件有49957289167B,大家一看这么一长串的数字后面单位是字节B,还是不知道这个文件的大小是一个什么概念,我们把它转换成GB为单位,就是46.53GB.用下面这些函数就可以完 ...
- java支持跨平台获取cpuid、主板id、硬盘id、mac地址 (兼容windows、Linux)
windows: package cn.net.comsys.helper.system.info; import java.io.BufferedReader; import java.io.F ...
- 关于linux asp.net MVC网站中 httpHandlers配置无效的处理方法
近期有Jexus用户反映,在Linux ASP.NET MVC网站的Web.config中添加 httpHandlers 配置用于处理自定义类型,但是在运行中并没有产生预期的效果,服务器返回了404( ...
- linux /proc/meminfo 文件分析(转载)
cat /proc/meminfo 读出的内核信息进行解释,下篇文章会简单对读出该信息的代码进行简单的分析. # cat /proc/meminfo MemTotal: kB MemFr ...
- jquery numberbox赋值
numberbox不能使用$('#id').val( '');只能使用$('#id').numberbox('setValue','');
- Java 串口通信
在Windows系统下,用Java开发串口通信相关的程序时,需要用到几个文件. (1)win32com.dll 要放在jdk\jre\bin目录下. (2)comm.jar 和javax.comm.p ...
- C和指针 第十章 结构和联合 习题
1. 记账信息结构联合 typedef struct { unsigned int areaNum; unsigned int transNum; unsigned int station; } ph ...