CF697C-考虑二叉树的LCA的性质

Posted hans774882968

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF697C-考虑二叉树的LCA的性质相关的知识,希望对你有一定的参考价值。

传送门

题意

给你一个可以认为是无穷大的完全二叉树,初始边权均为0。有两种操作:

  • 输入u,v,w,把uv的唯一路径的每条边的边权都加上w
  • 输入u,v,求uv的路径长度

操作个数1000,点的编号范围1e18,1-indexed。

思路

树上唯一路径,必定是围绕LCA讨论。并且有一个常见且重要的性质:二叉树的点u的祖先(1-indexed),就是u的二进制的高若干位。所以求LCA的函数是可以十分方便地写出来的,模仿倍增LCA模板的一些技巧即可。

int DEP(LL x){
    int ans = 0;
    while(x) x >>= 1,++ans;
    return ans;
}

LL LCA(LL x,LL y){
    if(x < y) swap(x,y);
    int dx = DEP(x),dy = DEP(y);
    x >>= (dx-dy);
    if(x == y) return x;
    for(;x != y;x >>= 1,y >>= 1);
    return x;
}

又因为这个二叉树高度只有60,所以两种操作我们都可以直接暴力往上爬,爬到LCA为止。

暴力爬的过程需要获取边权,所以我们定义fa数组。fa[u]表示点uu>>1的边的边权。因为u值大,所以数组要用map代替。如果!fa.count(u),则认为边权为0。

于是两种操作都是很简单的。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 100000 + 5;

int n,m;
map<LL,LL> fa;

void dbg(){puts("");}
template<typename T, typename... R>void dbg(const T &f, const R &... r) {
    cout << f << " ";
    dbg(r...);
}
template<typename Type>inline void read(Type &xx){
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;
}

int DEP(LL x){
    int ans = 0;
    while(x) x >>= 1,++ans;
    return ans;
}

LL LCA(LL x,LL y){
    if(x < y) swap(x,y);
    int dx = DEP(x),dy = DEP(y);
    x >>= (dx-dy);
    if(x == y) return x;
    for(;x != y;x >>= 1,y >>= 1);
    return x;
}

int main(int argc, char** argv) {
    read(m);
    while(m--){
        int op;read(op);
        if(op == 1){
            LL x,y,w;read(x);read(y);read(w);
            LL lca = LCA(x,y);
            for(;x != lca;x >>= 1) fa[x] += w;
            for(;y != lca;y >>= 1) fa[y] += w;
        }
        else{
            LL x,y;read(x);read(y);
            LL lca = LCA(x,y);
            LL ans = 0;
            for(;x != lca;x >>= 1){
                if(fa.count(x)) ans += fa[x];
            }
            for(;y != lca;y >>= 1){
                if(fa.count(y)) ans += fa[y];
            }
            printf("%lld\\n",ans);
        }
    }
    return 0;
}

以上是关于CF697C-考虑二叉树的LCA的性质的主要内容,如果未能解决你的问题,请参考以下文章

C语言 二叉树与堆

C语言 二叉树与堆

C语言 二叉树与堆

C语言 二叉树与堆

完全二叉树+暴力预处理+归并排序——cf894D

二叉树的定义常见的性质及其存储结构(C语言)