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 ...
随机推荐
- 选择CRM
第一:可扩展和定制 选择CRM系统一定要注意系统扩展性,要用发展的眼光去审视公司的CRM需求,所以CRM系统必须具有一定的扩展性,从而满足不断变化的公司需求.而那些看起来功能和强大不能扩展看起来貌似也 ...
- IIS如何配置可以下载APK、IPA文件
解决步骤: 1).打开IIS服务管理器,找到服务器,右键-属性,打开IIS服务属性: 2.单击MIME类型下的“MIME类型”按钮,打开MIME类型设置窗口: 3).单击“新建”,建立新的MIME类型 ...
- codevs 2988 保留小数 2
2988 保留小数 2 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题目描述 Description 这个难度是吸引你点进来的.(其实难度挺 ...
- SQL 事务回滚
事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便服 ...
- <<< 入侵网站类提权注入教程
---------------------------------------入侵类教程-------------------------------------------------------- ...
- 构建兼容浏览器的Angularjs web应用
背景 随着mvvm逐渐成熟,现在使用jQuery构建web应用已经显得过时了,而且使用jQuery需要编写更多的代码去控制dom的取值.赋值.绑定事件等,而mvv从底层实现了对以上操作的支持,让程序员 ...
- web在线打印,打印阅览,打印维护,打印设计
winform打印的方案比较多,实现也比较容易,而且效果也非常炫:但现在越来越多的系统是web系统,甚至是移动端.网上也有非常的web打印方案,但各式各样的问题非常多,比如js兼容性,稳定性等一直缠绕 ...
- 使用excel计算指数平滑和移动平均
指数平滑法 原数数据如下: 点击数据——数据分析 选择指数平滑 最一次平滑 由于我们选择的区域是B1:B22,第一个单元格“钢产量”,被当做标志,所以我们应该勾选标志.当我们勾选了标志后,列中的第 ...
- 搭建XMPP学习环境
XMPP(Extensible Messaging and Presence Protocol,前称Jabber)是一种以XML为基础的开放式IM协议.xmpp被人熟知,google talk肯定有一 ...
- 关于CDN的认识
传统的未加缓存服务的访问过程: 用户提交域名→浏览器对域名进行解释→得到目的主机的IP地址→根据IP地址访问发出请求→得到请求数据并回复 由上可见,用户访问未使用CDN缓存网站的过程为: 1).用户向 ...