codeforces 593D 树链剖分

题目链接
新地址链接
给出一棵树,每棵树有value值,两种操作:1 u v x, 用x依次除以u到v路径上的数,然后
输出x,2 p x, 把第p条边的权值改为x. 直接树链剖分,然后用线段树维护乘积即可。注意
乘积可能爆long long , 可以用inf/a如果

#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
using namespace std; 
typedef long long Long;
const int maxn = 2e5 + 10;
const int maxe = maxn*2;
const Long inf = 1e18 + 10000;

struct divTree
{
    void add_edge(int u, int v, Long c)
    {
        edges[cnt_edge] = Edge(u, v, c, fir[u]);
        fir[u] = cnt_edge++;
    }
    void init()
    {
        memset(fir, -1, sizeof(fir));
        cnt_edge = 0;
    }
    void dfs1(int u)
    {
        sz[u] = 1; son[u] = 0;
        for (int e = fir[u]; e != -1; e = edges[e].x)
        {
            int v = edges[e].v; if (v == fa[u]) continue;
            dep[v] = dep[u]+1; fa[v] = u;
            dfs1(v);
            sz[u] += sz[v];
            if (sz[son[u]] < sz[v])
            {
                son[u] = v;
            }
        }
    }
    void dfs2(int u)
    {
        if (son[u]) 
        {
            faEdge[son[u]] = ++no;
            train[son[u]] = train[u];
            dfs2(son[u]);
        }
        for (int e = fir[u]; e != -1; e = edges[e].x)
        {
            int v = edges[e].v; if (v == fa[u]) continue;
            if (v == son[u])
            {
                val[faEdge[v]] = edges[e].c;
                mp[e/2+1] = faEdge[v];
            }
            else
            {
                faEdge[v] = ++no;
                val[no] = edges[e].c; mp[e/2+1] = no;
                train[v] = v;
                dfs2(v);
            }
        }
    }
    void pushUp(int o)
    {
        if (inf / sum[o<<1] < sum[o<<1|1]) sum[o] = inf;
        else sum[o] = sum[o<<1]*sum[o<<1|1];
    }
    void build(int o, int l, int r)
    {
        if (l == r)
        {
            sum[o] = val[l];
            return ;
        }
        int m = (l + r) >> 1;
        build(lson); build(rson);
        pushUp(o);
    }
    void run(int rt)
    {
        dep[rt] = 1; fa[rt] = rt;
        dfs1(rt);
        no = 0; train[rt] = rt;
        dfs2(rt);
        build(1, 1, no);
    }

    void update(int p, Long v, int o, int l, int r)
    {
        if (l == r)
        {
            sum[o] = v;
            return ;
        }
        int m = (l + r) >> 1;
        if (p <= m) update(p, v, lson);
        else update(p, v, rson);
        pushUp(o);
    }
    Long query(int a, int b, int o, int l, int r)
    {
        if (a <= l && b >= r)
        {
            return sum[o];
        }
        int m = (l + r) >> 1;
        if (a <= m && b > m)
        {
            Long v1 = query(a, b, lson), v2 = query(a, b, rson);
            if (inf/v1 < v2) return inf;
            else return v1*v2;
        }
        else if (a <= m) return query(a, b, lson);
        else return query(a, b, rson);
    }
    Long gao(int u, int v)
    {
        Long ret = 1;
        for (int fu=train[u], fv=train[v]; fu != fv; fu=train[u],fv=train[v])
        {
            if (dep[fu] < dep[fv])
            {
                swap(u, v); swap(fu, fv);
            }
            Long now = query(faEdge[fu], faEdge[u], 1, 1, no);
            if (inf/now < ret) ret = inf;
            else ret = ret * now;
            u = fa[fu];
        }
        if (u == v) return ret;
        if (dep[u] > dep[v]) swap(u, v);
        Long now = query(faEdge[son[u]], faEdge[v], 1, 1, no);
        if (inf/now < ret) ret = inf;
        else ret = ret * now;
        return ret;
    }   
    struct Edge
    {
        int u, v, x;
        Long c;
        Edge(int u = 0, int v = 0, Long c = 0, int x = 0) : u(u), v(v), c(c), x(x) {}
    } edges[maxe];
    int fir[maxn], cnt_edge, no;
    int dep[maxn], sz[maxn], fa[maxn], son[maxn];
    int train[maxn], mp[maxn], faEdge[maxn];
    Long val[maxn], sum[maxn<<2];
} divt;
int main()
{
    int n, m; scanf("%d%d", &n, &m);

    divt.init();
    for (int i = 0; i < n-1; i++)
    {
        int u, v; Long c; scanf("%d%d%I64d", &u, &v, &c);
        divt.add_edge(u, v, c);
        divt.add_edge(v, u, c);
    }
    divt.run(1);
    for (int i = 0; i < m; i++)
    {
        int cmd; scanf("%d", &cmd);
        if (cmd == 1) 
        {
            int a, b; Long v; scanf("%d%d%I64d", &a, &b, &v);
            Long now = divt.gao(a, b);
            printf("%I64d\n", v/now);
        } 
        else 
        {
            int p; Long v; scanf("%d%I64d", &p, &v);
            divt.update(divt.mp[p], v, 1, 1, divt.no);
        }
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值