hdu3078(lca / RMQ在线)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3078

题意: 给出一棵 n 个点的带点权值的树, 接下来有 q 组形如 k, x, y 的输入, 若 k == 0 则将 x 点的权值替换成 y, 否则输出 x 到 y 之间顶点地 k 大的权值.

思路: 用一个数组 val 记录一下每个顶点的权值, 对于k == 0, 直接令 val[x] = y 即可 .

对于询问, 可以先求出 lca, 再记录一下路径上的顶点的权值, sort 一下, 输出第 k 大的即可.

代码:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <math.h>
 4 #include <string.h>
 5 #include <algorithm>
 6 #include <vector>
 7 using namespace std;
 8
 9 const int MAXN = 8e4 + 10;
10 vector<int> vt[MAXN];
11 int dp[MAXN << 1][30];
12 int first[MAXN], ver[MAXN << 1], deep[MAXN << 1];
13 int pre[MAXN], val[MAXN], yy[MAXN], ip = 0, indx = 0;
14
15 bool cmp(int x, int y){
16     return x > y;
17 }
18
19 void dfs(int u, int h, int fa){
20     pre[u] = fa;
21     ver[++indx] = u;
22     deep[indx] = h;
23     first[u] = indx;
24     for(int i = 0; i < vt[u].size(); i++){
25         int v = vt[u][i];
26         if(v != fa){
27             dfs(v, h + 1, u);
28             ver[++indx] = u;
29             deep[indx] = h;
30         }
31     }
32 }
33
34 void ST(int n){
35     for(int i = 1; i <= n; i++){
36         dp[i][0] = i;
37     }
38     for(int j = 1; (1 << j) <= n; j++){
39         for(int i = 1; i + (1 << j) - 1 <= n; i++){
40             int x = dp[i][j - 1], y = dp[i + (1 << (j - 1))][j -1];
41             dp[i][j] = deep[x] < deep[y] ? x : y;
42         }
43     }
44 }
45
46 int RMQ(int l, int r){
47     int len = log2(r - l + 1);
48     int x = dp[l][len], y = dp[r - (1 << len) + 1][len];
49     return deep[x] < deep[y] ? x : y;
50 }
51
52 int LCA(int x, int y){
53     int l = first[x];
54     int r = first[y];
55     if(l > r) swap(l, r);
56     int pos = RMQ(l, r);
57     return ver[pos];
58 }
59
60 void path(int x, int root, int &pos){
61     while(x != root && x != -1){
62         yy[pos++] = val[x];
63         x = pre[x];
64     }
65 }
66
67 void solve(int x, int y, int k){
68     int pos = 0, lca = LCA(x, y);
69     path(x, lca, pos);
70     path(y, lca, pos);
71     yy[pos++] = val[lca];
72     if(pos < k) puts("invalid request!");
73     else{
74         sort(yy, yy + pos, cmp);//注意是从大到小的第 k 大!!!!!!!!!
75         printf("%d\n", yy[k - 1]);
76     }
77 }
78
79 int main(void){
80     int n, q, x, y, op;
81     scanf("%d%d", &n, &q);
82     for(int i = 1; i <= n; i++){
83         scanf("%d", &val[i]);
84     }
85     for(int i = 1; i < n; i++){
86         scanf("%d%d", &x, &y);
87         vt[x].push_back(y);
88         vt[y].push_back(x);
89     }
90     dfs(1, 1, -1);
91     ST(indx);
92     while(q--){
93         scanf("%d%d%d", &op, &x, &y);
94         if(!op) val[x] = y;
95         else solve(x, y, op);
96     }
97     return 0;
98 }

时间: 2024-11-09 00:56:58

hdu3078(lca / RMQ在线)的相关文章

POJ 1330 Nearest Common Ancestors LCA(在线RMQ,离线Tarjan)

链接:http://poj.org/problem?id=1330 题意:只看题目就知道题目是什么意思了,最近公共祖先,求在一棵树上两个节点的最近公共祖先. 思路:求最近公共祖先有两种算法,在线和离线,在线方法是用RMQ求LCA,一句话总结就是在从DFS时,从第一个点到第二个点的最短路径中深度最浅的点就是公共祖先,用RMQ处理,一般问题的最优解决方式的复杂度是O(NlogN)的预处理+N*O(1)的查询.离线方法是Tarjan算法,将所有询问的两个点都记录下来,在DFS过程中不断将每个点自身作为

hdu 3078(LCA的在线算法)

Network Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 847    Accepted Submission(s): 347 Problem Description The ALPC company is now working on his own network system, which is connecting all

zoj3195(lca / RMQ离线)

题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3195 题意: 给出一棵 n 个节点的带边权的树, 有 q 组形如 x, y, z 的询问, 输出 x, y, z之间的最短路径. 思路: 在纸上画下不难发现 x, y, z之间的最短路径就是 x, y, z 两两之间的最短路径和的一半. 我们可以通过 lca 模板求出 x, y, z 两两之间的最短路径, 然后再算下 x, y, z三点之间的最短路径即可. 这

UESTC 912 树上的距离 --LCA+RMQ+树状数组

1.易知,树上两点的距离dis[u][v] = D[u]+D[v]-2*D[lca(u,v)] (D为节点到根节点的距离) 2.某条边<u,v>权值一旦改变,将会影响所有以v为根的子树上的节点到根节点的距离,很明显,DFS一遍后以v为根的子树在DFS序列中是连续的一段,及转化为区间更新问题,可以用树状数组. 做法:先把求LCA解决,LCA可以转化为RMQ问题,可参见:LCA转RMQ, 即转化为LCA(T,u,v) = RMQ(B,pos[u],pos[v]),其中B为深度序列.预先DFS可以处

hdu2874(lca / tarjan离线 + RMQ在线)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2874 题意: 给出 n 个顶点 m 条边的一个森林, 有 k 个形如 x y 的询问, 输出 x, y 之间的最短路径. 思路: 如果将森林换成一棵树的话就是一道 lca 模板题了, 不过本题需要稍作改动. 解法1: tarjan 只需要先判断一下 x, y 是否在一颗树里面就 ok 了, 不过这道题的询问有点多, 很容易 mle. 代码: 1 #include <iostream> 2 #in

LCA最近公共祖先 ST+RMQ在线算法

对于这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O(n); 先介绍在线算法: 1) dfs: 对于图所示的树,我们从根节点1开始dfs,按照先序访问(不算完全的先序),那么它访问顺序就是1 -> 2 -> 4 -> 2 -> 5 -> 7 -> 5 -> 8 -> 5 -> 2 -> 1 -> 3 -> 1 然后用数组first存第一次访问到该点时的时间(也就是访问顺序里面

LCA(倍增在线算法) codevs 2370 小机房的树

codevs 2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计

POJ 1470 Closest Common Ancestors(LCA&amp;RMQ)

题意比较费劲:输入看起来很麻烦.处理括号冒号的时候是用%1s就可以.还有就是注意它有根节点...Q次查询,我是用在线st做的. /************************************************************************* > File Name: 3.cpp > Author: Howe_Young > Mail: [email protected] > Created Time: 2015年10月08日 星期四 19时03分

学习 LCA&amp;&amp;RMQ

参考:点击打开链接 点击打开链接      点击打开链接(一些总结) 点击打开链接(不错的模板) 题目:点击打开链接 花了4天时间做完了这个专题,LCA的问题用处还是很大,同时能体会RMQ的ST算法中dp的味道.基本方法就是ST,LCA转RMQ,LCA的Tarjan,LCA倍增(这个可存储边权) 这个专题后面四道题都非常好,推荐大家做做. 细节: 1. ST方法2^i 包含自己,因此其真实只包含到i+2^k-1的范围. 2. Tarjan一般都很快,但不适合修改类型的问题,关于权值长度之类的,S