[CodeForces 593D]Happy Tree Party[LCA][路径压缩]

题目链接: [CodeForces 593D]Happy Tree Party[LCA][路径压缩]

题意分析:

给出两个操作,1和2。

1代表查询结点a到结点b之间最短路径,将路径上的权值对y进行向下求整,输出结果。

2更改某个结点的权值

解题思路:

y最大1e18,对于除数为大于1的数字来说,最多除60次就可以让y变成0了。所以用lca不断除,当结果是0时就返回结果。

不过还要考虑除数为1的情况,这就会使得路径变得很长导致T了。所以要路径压缩一下。

个人感受:

比赛的时候知道LCA,但是觉得会T,没考虑过向下除不超过60次就变0了。

具体代码如下:

#include<cstdio>
#include<iostream>
#include<queue>
#define ll long long
#define pr(x) cout << #x << " = " << (x) << '\n';
using namespace std;

const int INF = 0x7f7f7f7f;
const int MAXN = 2e5 + 111;

struct Node{
    int v, id;
    ll w;
    Node(int _v, ll _w, int _id): v(_v), w(_w), id(_id) {}
};

int dep[MAXN], fa[MAXN], par[MAXN], point[MAXN]; // point:点所对应的边id
ll val[2 * MAXN];
vector<Node> G[MAXN];

int find(int x)
{
    return x == par[x] ? x : par[x] = find(par[x]);
}

void dfs(int u, int p, int d)
{
    dep[u] = d;
    fa[u] = p;
    for (int i = 0; i < G[u].size(); ++i)
    {
        Node &e = G[u][i];
        if (e.v != p)
        {
            val[e.v] = e.w; // 将点所对应的权值转换为以这个结点为结尾的边对应的权值来记录
            point[e.id] = e.v; // 用id来查找点
            dfs(e.v, u, d + 1);
        }
    }
}

ll lca(int u, int v, ll w)
{
    u = find(u), v = find(v);
    while (u != v) // 每次将较低的结点向上提升,不断除
    {
        if (dep[u] < dep[v]) swap(u, v);
        w /= val[u]; u = find(fa[u]);
        if (w == 0) return 0;
    }
    return w;
}

void update(int u) // 如果该点权值为一,那么就让它的祖先指向它的父亲结点
{
    par[u] = fa[u];
}

int main()
{
    int n, m, u, v, op;
    ll w;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) G[i].clear(), par[i] = i;
    for (int i = 1; i < n; ++i)
    {
        scanf("%d%d%I64d", &u, &v, &w);
        G[u].push_back(Node(v, w, i));
        G[v].push_back(Node(u, w, i));
    }

    dfs(1, -1, 0);

    for (int i = 2; i <= n; ++i) if (val[i] == 1) update(i);

    int a, b, p;
    ll y, c;
    while (m --)
    {
        scanf("%d", &op);
        if (op == 1)
        {
            scanf("%d%d%I64d", &a, &b, &y);
            printf("%I64d\n", lca(a, b, y));
        }
        else
        {
            scanf("%d%I64d", &p, &c);
            int v = point[p]; val[v] = c;
            if (c == 1) update(v);
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值