POJ 3728 离线 LCA

题意很简单

给一个树(n < 5w) 每个点有个权值,代表商品价格

若干个询问(5w)

对每个询问,问的是从u点走到v点(简单路径),商人在这个路径中的某点买入商品,然后在某点再卖出商品,   最大可能是多少

注意一条路径上只能买卖一次,先买才能卖

用的方法是离线LCA,在上面加了一些东西

对于一个询问, 假设u,v的LCA是f

那么有三种可能, 一个是从u到f 买卖了。 一个是从f到v买卖了,  一个是从u到f之间买了,从v到f卖了

从u到f 我们称为up,  从f到v我们称为down,而从u到f买然后在f到v卖就是求u到f的最小值和f到v的最大值。

我们要分别求这三个值

实际上就是在离线tarjan求LCA的过程中求出的

对于每个点, 我们进行dfs的时候,查看于其相关的询问,

假设当前点是u, 询问的点是v, u和v的LCA是f,如果v已经dfs过了,说明v在并查集中的祖先就是u,v的LCA  f点,

将该询问加入到f的相关集合中,等f所有的子节点都处理过后再去处理f, 就可以发现,一切都是顺其自然了

在这些处理过程中,up和down以及u,v到f的最大值最小值  都可以在并查集求压缩路径的过程中更新。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <map>
#include <ctime>
#define MAXN 52222
#define MAXM 222222
#define INF 1000000001
using namespace std;
vector<int>g[MAXN], st[MAXN], ed[MAXN], id[MAXN], ask[MAXN], pos[MAXN];
int mx[MAXN], mi[MAXN], up[MAXN], down[MAXN], vis[MAXN], fa[MAXN], ans[MAXN];
int n, Q;
int find(int x) {
    if(x == fa[x]) return x;
    int y = fa[x];
    fa[x] = find(y);
    up[x] = max(up[x], max(mx[y] - mi[x], up[y]));
    down[x] = max(down[x], max(mx[x] - mi[y], down[y]));
    mx[x] = max(mx[x], mx[y]);
    mi[x] = min(mi[x], mi[y]);
    return fa[x];
}
void tarjan(int u) {
    vis[u] = 1;
    for(int i = 0; i < ask[u].size(); i++) {
        int v = ask[u][i];
        if(vis[v]) {
            int t = find(v);
            int z = pos[u][i];
            if(z > 0) {
                st[t].push_back(u);
                ed[t].push_back(v);
                id[t].push_back(z);
            } else {
                st[t].push_back(v);
                ed[t].push_back(u);
                id[t].push_back(-z);
            }
        }
    }
    for(int i = 0; i < g[u].size(); i++) {
        int v = g[u][i];
        if(!vis[v]) {
            tarjan(v);
            fa[v] = u;
        }
    }
    for(int i = 0; i < st[u].size(); i++) {
        int a = st[u][i];
        int b = ed[u][i];
        int t = id[u][i];
        find(a);
        find(b);
        ans[t] = max(up[a], max(down[b], mx[b] - mi[a]));
    }
}

int main() {
        scanf("%d", &n);
        int u, v, w;

        for(int i = 1; i <= n; i++) {
            scanf("%d", &w);
            mx[i] = mi[i] = w; fa[i] = i;
        }
        for(int i = 1; i < n; i++) {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
            g[v].push_back(u);

        }
        scanf("%d", &Q);
        for(int i = 1; i <= Q; i++) {
            scanf("%d%d", &u, &v);
            ask[u].push_back(v);
            pos[u].push_back(i);
            ask[v].push_back(u);
            pos[v].push_back(-i);
        }
        tarjan(1);
        for(int i = 1; i <= Q; i++) printf("%d\n", ans[i]);

    return 0;
}
时间: 2024-10-10 10:37:43

POJ 3728 离线 LCA的相关文章

poj 3728 The merchant(LCA)

Description There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and wants to earn as much money as possible in each path. When he move along a path, he can choose on

HDU 5452(离线LCA,树形dp

题目:给出一个图和它的一个生成树,要求删除生成树上的一条边和若干其他边,使得图不连通.求能删除的最小边数. 思路:考虑dp,对于树上的一条边,删除之后,还需要删除的边的数目就是从这个节点的子树连向其他子树或祖先节点的边数.那么对于一棵子树来说这个统计数目就等于其子树的数目之和减去它的子树之间的边数.减的这一部分可以在tarjan离线LCA算法中实现. /* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400

HDU 2586 How far away ? 离线lca模板题

How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8712    Accepted Submission(s): 3047 Problem Description There are n houses in the village and some bidirectional roads connecting

HDU 5044 离线LCA算法

昨天写了HDU 3966 ,本来这道题是很好解得,结果我想用离线LCA 耍一把,结果发现离线LCA 没理解透,错了好多遍,终得AC ,这题比起 HDU 3966要简单,因为他不用动态查询.但是我还是错了好多遍  T^T... http://acm.split.hdu.edu.cn/showproblem.php?pid=5044 不多说了  思想不是很清楚的可以看一看我的上一篇博文 HDU 3966 直接贴代码 1 #include<iostream> 2 #include<stdio.

hdoj 2586 How far away ? 【Tarjan离线LCA】

题目:hdoj 2586 How far away ? 题意:给出一个有权树,求任意两点的之间的距离. 分析:思想就是以一个点 root 作为跟变成有根数,然后深搜处理处所有点到跟的距离.求要求的两个点的LCA(最近公共祖先), 然后ans = dis[x] + dis[y] - 2 * dis[LCA(x,y)],可以画图分析一下就知道. 求LCA我用的是Tarjan离线lca,由于询问次数很多,所以这个比较快. AC代码: #include <iostream> #include <

hihoCoder #1067 : 最近公共祖先&#183;二 [ 离线LCA tarjan ]

传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站,这个网站可以计算出某两个人的所有共同祖先中辈分最低的一个是谁.远在美国的他们利用了一些奇妙的技术获得了国内许多人的相关信息,并且搭建了一个小小的网站来应付来自四面八方的请求. 但正如我们所能想象到的……这样一个简单的算法并不能支撑住非常大的访问量,所以摆在小Hi和小Ho面前的无非两种选择: 其一是

poj 1470 Closest Common Ancestors 【Tarjan 离线 LCA】

题目:poj 1470 Closest Common Ancestors 题意:给出一个树,一些询问.求LCA的个数. 分析:很简单的模板题目,但是模板不够优秀,一直wa...RE,各种错误一下午,终于发现自己模板的漏洞了. AC代码: #include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; #define N 1010 #

POJ - 3728 The merchant(dp+LCA)

题目大意:给出N个点,和每个点物品的售价,现在有一个商人,要从u点到v点,他想在路上多赚点钱.他可以从一个城市买物品,然后再卖到另一个城市,但买卖只允许一次,且不能回头走 问最多能赚多少 解题思路:果然智商捉急了.. up数组纪录当前点到lca的最大利润 down数组纪录lca到当前点的最大利润 Max数组lca到当前点的最大值 Min纪录当前点到lca的最小值 这样的话,执行tarjan的时候,就可以更新一下这些值了 首先,答案的话肯定是max(max(up, down), Max - Min

POJ 1330 Nearest Common Ancestors(Tarjan离线LCA)

Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of