首页 > 其他分享 >动态树直径小记

动态树直径小记

时间:2024-01-31 22:22:38浏览次数:32  
标签:Node nil rs sum fa ls 直径 动态 小记

本文采用 BY-NC-SA 协议发布。

要求:给你一棵树,边带权,每次断边连边(保证合法且仍是树),在线求每次修改后的直径。

LCT

(咕)

Top Tree

拆边,然后用 negiizhao 论文里的方法维护。

实现时注意,翻转标记会影响合并的信息,要 swap 一下。

#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <vector>
#include <cassert>
#define UP(i,s,e) for(auto i=s; i<e; ++i)
using std::cin; using std::cout;
using ll = long long;
struct Info{
    ll ml, mr, mm, lr;
    // m: inside cluster
    // l: min dep
    // r: max dep
    Info(){}
    Info(int a, int b, int c, int d):ml(a), mr(b), mm(c), lr(d){}
    Info operator>>(Info b){  // COMPRESS
        Info ans;
        ans.mm = std::max({mm, b.mm, mr + b.ml});
        ans.ml = std::max(ml, lr + b.ml);
        ans.mr = std::max(b.mr, b.lr + mr);
        ans.lr = lr + b.lr;
        return ans;
    }
    Info operator<<(Info b){ // RAKE
        Info ans;
        ans.mm = std::max({mm, b.mm, ml + b.ml});
        ans.ml = std::max(ml, b.ml);
        return ans;
    }
};
constexpr int N = 2e5;
namespace TopTree{ // }{{{
enum NT{ COMPRESS, RAKE };
struct Node{
    Node *fa, *ls, *ms, *rs;
    Info sum; // heavy_info, light_info
    int len; // to fa
    NT typ;
    bool rev;
} nil_, *nil = &nil_, nds[N*2];
std::vector<int> rubbish;
Node *nnod(){
    static int cnt = 0;
    if(rubbish.empty()) return nds + cnt++;
    Node *p = nds + rubbish.back();
    rubbish.pop_back();
    return p;
}
void erase(Node *x){ rubbish.push_back(x - nds); }
void flip(Node *x){ x->rev ^= 1; std::swap(x->sum.ml, x->sum.mr); }
bool nroot(Node *x){ return x->fa->ls == x || x->fa->rs == x; }
bool isrs(Node *x){ return x == x->fa->rs; }
void pushup(Node *x){
    if(x->typ == COMPRESS){
        Info my = Info(x->ms->sum.ml + x->len, x->ms->sum.ml + x->len,
                std::max({x->ms->sum.mm, x->ms->sum.ml + x->len}), x->len);
        x->sum = x->ls->sum >> my >> x->rs->sum;
        if(x->rev) std::swap(x->sum.ml, x->sum.mr);
    } else {
        x->sum = x->ls->sum << x->ms->sum << x->rs->sum;
    }
}
void pushdown(Node *x){
    if(x->rev == false || x == nil) return;
    x->rev = false;
    flip(x->ls);
    flip(x->rs);
    std::swap(x->ls, x->rs);
    pushup(x);
}
void pushdddd(Node *x){
    if(nroot(x)) pushdddd(x->fa);
    pushdown(x);
}
void setfa(Node *x, Node *f, int pos){
    if(x != nil) x->fa = f;
    if(pos == 0) f->ls = x;
    else if(pos == 1) f->rs = x;
    else f->ms = x;
}
void rotate(Node *x){
    if(x == nil || !nroot(x)) return;
    Node *y = x->fa, *z = y->fa;
    if(z != nil){
        if(z->ls == y) z->ls = x;
        if(z->ms == y) z->ms = x;
        if(z->rs == y) z->rs = x;
    }
    if(isrs(x)){
        setfa(x->ls, y, 1);
        setfa(y, x, 0);
    } else {
        setfa(x->rs, y, 0);
        setfa(y, x, 1);
    }
    x->fa = z;
    pushup(y);
    pushup(x);
}
void splay(Node *x, Node *to = nil){
    pushdddd(x);
    for(Node *y; y = x->fa, nroot(x) && y != to; rotate(x)){
        if(y->fa != to && nroot(y)){
            rotate(isrs(y) ^ isrs(x) ? x : y);
        }
    }
}
void unuse(Node *x){
    assert(x->typ == RAKE);
    if(x->ls == nil){
        setfa(x->rs, x->fa, 2);
    } else {
        Node *p = x->ls;
        pushdown(p);
        while(p->rs != nil) p = p->rs, pushdown(p);
        splay(p, x);
        setfa(x->rs, p, 1);
        setfa(p, x->fa, 2);
        pushup(p);
        pushup(x->fa);
    }
    erase(x);
}
void splice(Node *x){
    splay(x);
    Node *y = x->fa;
    splay(y);
    pushdown(x);
    if(y->rs != nil){
        std::swap(x->ms->fa, y->rs->fa);
        std::swap(x->ms, y->rs);
        pushup(x);
    } else {
        setfa(x->ms, x->fa, 1);
        unuse(x);
    }
    pushup(y);
}
void access(Node *x){
    splay(x);
    if(x->rs != nil){
        Node *y = nnod();
        y->len = y->rev = 0;
        y->typ = RAKE;
        setfa(x->ms, y, 0);
        setfa(x->rs, y, 2);
        x->rs = y->rs = nil;
        setfa(y, x, 2);
        pushup(y);
        pushup(x);
    }
    Node *p = x;
    while(p->fa != nil){
        splice(p->fa);
        p = p->fa;
        pushup(p);
    }
    splay(x);
}
void mkroot(Node *x){ access(x); flip(x); }
void expose(Node *x, Node *y){ mkroot(x); access(y); }
Node *findrt(Node *x){
    access(x);
    pushdown(x);
    while(x->ls != nil) x = x->ls, pushdown(x);
    splay(x);
    return x;
}
void link(Node *x, Node *y){
    //if(findrt(x) == findrt(y)) return;
    access(x);
    mkroot(y);
    setfa(y, x, 1);
    pushup(x);
}
void cut(Node *x, Node *y){
    expose(x, y);
    if(y->ls != x || x->rs != nil) return;
    x->fa = y->ls = nil;
    pushup(y);
}
} // {}}}
namespace m{ // }{{{
int in, iq;
using TopTree::Node;
using TopTree::nds;
using TopTree::nil;
std::unordered_map<ll, Node*> lnk;
ll geted(int x, int y){
    if(x > y) std::swap(x, y);
    ll ed = ll(x) << 32 | y;
    return ed;
}
ll sum_edge;
void iN(){
    cin.tie(0)->sync_with_stdio(0);
    cin >> in >> iq;
    UP(i, 0, in){
        Node *p = TopTree::nnod();
        p->fa = p->ls = p->ms = p->rs = nil;
        p->typ = TopTree::COMPRESS;
    }
    UP(i, in, in+in-1){
        int ix, iy, iw; cin >> ix >> iy >> iw;
        ix--, iy--;
        sum_edge += iw;
        ll ed = geted(ix, iy);
        Node *p = TopTree::nnod();
        p->fa = p->ls = p->ms = p->rs = nil;
        p->typ = TopTree::COMPRESS;
        p->len = iw;
        p->sum = {iw, iw, iw, iw};
        TopTree::link(nds+ix, p);
        TopTree::link(nds+iy, p);
        lnk[ed] = p;
    }
    TopTree::access(nds);
    cout << nds->sum.mm << '\n';
}
void work(){
    while(iq--){
        int ix, iy, ip, q, iw;
        cin >> ix >> iy >> ip >> q >> iw;
        ix--, iy--, ip--, q--;
        ll olded = geted(ix, iy);
        ll newed = geted(ip, q);
        Node *p = lnk[olded];
        lnk.erase(olded);
        sum_edge -= p->len;
        TopTree::cut(nds+ix, p);
        TopTree::cut(nds+iy, p);
        p->len = iw;
        sum_edge += iw;
        TopTree::link(nds+ip, p);
        TopTree::link(p, nds+q);
        lnk[newed] = p;
        cout << p->sum.mm << '\n';
    }
}
} // {}}}
int main(){m::iN(); m::work(); }

标签:Node,nil,rs,sum,fa,ls,直径,动态,小记
From: https://www.cnblogs.com/x383494/p/18000262

相关文章

  • Vue 搭配GSAP实现颜色动态渐变
    重点使用reactive构造响应式的对象存储颜色,使用gsap.to操作响应式对象实现颜色渐变代码lettoTimeLine:TweenletoverTimeLine:TweentypeColor={value:string}typeTween=gsap.core.TweenconstaddItemColor=reactive<C......
  • 【京东云新品发布月刊】2024年1月产品动态来啦
     1)【莫奈可视化平台】新品上线京东莫奈可视化平台通过自由拖拽、图形化编辑、所见即所得的方式,快速实现极致酷炫、直观清晰的视觉场景,将海量繁杂数据背后所蕴含的价值更直观、深层、全面的展现出来,辅助决策者合理决策。2)【移动端应用监控SGM-mobile】新品上线移动端监控S......
  • element实现大图预览和图片动态加载
    element的el-image组件支持大图预览模式,但需要和小图模式配合使用,项目中刚好有需求需要直接使用大图预览并且需要支持图片的动态加载,研究了一下el-image组件的源码发现el-image组件是通过引用image-viewer组件实现的大图预览的,刚好可以利用一下!image-viewer属性urlList:图......
  • 动态 DP 学习笔记
    动态DPP4719动态DP给定一棵\(n\)(\(n\leqslant10^5\))个点的树,点带点权。有\(m\)(\(m\leqslant10^5\))次操作,每次操作给定\(x,y\),表示修改点\(x\)的权值为\(y\)。你需要在每次操作之后求出这棵树的最大权独立集的权值大小。首先考虑\(m=0\)时的做法,可以......
  • 【C语言进阶篇】动态内存常考笔试题
    (文章目录)......
  • 二维动态规划(下)
    二维动态规划(下)115.不同的子序列//自底向上intnumDistinct(char*s,char*t){constintMOD=1e9+7;intlenS=strlen(s);intlenT=strlen(t);//dp[i][j]表示在s中前缀长度为i的字符串所包含的所有子序列中,有多少个子序列等于t中前缀长度为j的......
  • onnx导出-多输入+动态维度
    onnx导出-多输入+动态维度目录onnx导出-多输入+动态维度常见问题多参数输入动态输入导出动态输入问题-无法修改维度重新定义onnx输出验证导出和测试多头输入多头输出参考资料常见问题多参数输入importnumpyasnpimportcv2importtorchimporttorch.nnasnnimporttorc......
  • 动态区间特殊值——线段树的简单应用
    目录问题引入简单介绍功能详情碎碎念问题引入很多地方写的是区间最值问题,感觉区间特殊值更好一些,区间gcd、前缀和都可以,问题描述大致就是给出一个数组,要求给出询问区间的特殊值,当然求和之类的可以用树状数组解决,但是最大、最小等等特殊值是不能转化为前缀和用树状数组解决的,因此......
  • SpringBoot实现动态数据源配置
    场景描述:前一阵子接手的新项目中需要使用2个数据源。一个叫行云数据库,一个叫OceanBase数据库。就是说,我有时候查询要查行云的数据,有时候查询要查OceanBase的数据,咋办?废话不多说,下面以mysql为例,开整。一、环境依赖<dependency><groupId>org.springframework.boot</gr......
  • JVS低代码表单引擎:实现下拉框数据来源动态化的解决方案
    下拉选项数据来源调用逻辑引擎的功能在于提供一个可视化的界面,使用户能够方便地配置和管理业务逻辑,实现数据的快速处理、业务模式的自动化和智能化。接下来我详细介绍JVS低代码中如何通过逻辑引擎获取下拉选项的数据来源,以及如何配置下拉框组件以实现这一功能。下拉选项数据来源调......