参考论文

求解范围:(动态树问题)

  • 树上路径查询、修改
  • 动态连边、删边
  • 换根
  • lca

算法逻辑

概念:

  • 类似树链剖分,把一棵树拆成许多链,每个链用splay维护(链上的为实边,否则为虚边),splay中以\(dep\)为关键字(左浅右深),splay里点之间用\(fa\)和\(son[0/1]\)连接,不同链之间用\(par\)连接(par是单向的(下->上))。

    \(par\)存在splay的根中,值为该splay中 \(dep\) 最小(浅)的父亲(可以想象一下跳到原树中的那条链的顶端的父亲)

流程:

access

  • 作用:将u往上到根的路径,拆成一条链
  • 操作:

    1.\(v\)为过程中一点,且到右儿子存在实边,则需要断开\(v\)与右端点的实边(变为虚边)。

    2.\(u\)沿着par往上跳(直到根),每次到一个新的splay就跟上一个splay链合并一下。(同时更新1)
  • Code:
void access(int x) {
int y=0;
while(x) {
splay(x);P_dw(x);
if(son[x][1]) fa[son[x][1]]=0,par[son[x][1]]=x;
son[x][1]=y;fa[y]=x; //??splay
P_up(x);
y=x;x=par[x];
}
}

LCA(x,y)

  • 操作:\(access(x)\),\(access(y)\)中\(y\)往上跳到与根在同一个splay里面时,所在的点\(d\)即为lca。
  • 证明:显然\(par\)的定义是到该splay树最浅的点的\(fa\),所以\(y\)往上跳,到根(\(x\))所在splay树中的点是其中最浅的点,又因为这个点深度+1刚好跳出该链树,\(x\)就经过不了,因此这个点也就是\(d\)。

小细节

  • \(par\)是需要存储于每个splay_tree的根处,所以每次splay后要手动更新赋值。
  • splay()前要手动递归从根到该点Pushdown。
  • 可以不用\(par\),只用\(fa\),不过要慢一些呀。

ps.还有很多其余的操作可以见下面这道题的代码:

OTOCI

    #include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
bool Lazy[N];
int val[N],son[N][2],sum[N];
int par[N],fa[N];
int q,n;
void P_up(int x) {sum[x]=val[x]+sum[son[x][0]]+sum[son[x][1]];}
void P_dw(int x) {
if(!Lazy[x])return;
swap(son[x][0],son[x][1]);
Lazy[son[x][0]]^=1,Lazy[son[x][1]]^=1;Lazy[x]=0;
}
bool Type(int x) {return son[fa[x]][1]==x;}
void rotate(int x) {
int y=fa[x],z=fa[y],k=Type(x);
fa[x]=z;if(z)son[z][Type(y)]=x;
son[y][k]=son[x][k^1];fa[son[y][k]]=y;
son[x][k^1]=y;fa[y]=x;
P_up(y);P_up(x);
}
void _spdw(int u,int x) {
if(!fa[u]) {par[x]=par[u];P_dw(u);return;}
_spdw(fa[u],x);
P_dw(u);
}
void splay(int x) {
_spdw(x,x);
for(int f=fa[x];f=fa[x];rotate(x)) {
if(fa[f]) rotate(Type(x)==Type(f)?f:x);
}
}
void access(int x) {
int y=0;
while(x) {
splay(x);P_dw(x);
if(son[x][1]) fa[son[x][1]]=0,par[son[x][1]]=x;
son[x][1]=y;fa[y]=x; //??splay
P_up(x);
y=x;x=par[x];
}
}
void mk_rt(int x) {access(x);splay(x);Lazy[son[x][0]]^=1;Lazy[son[x][1]]^=1;swap(son[x][0],son[x][1]);}
int Fd_rt(int x) {access(x);splay(x);while(son[x][0])x=son[x][0];splay(x);return x;}
void split(int x,int y) {mk_rt(x);access(y);splay(y);} //??
void Link(int x,int y) {mk_rt(x);par[x]=y;}
int Sum(int x,int y) {split(x,y);return sum[y];}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&val[i]),sum[i]=val[i];
scanf("%d",&q);
while(q--) {
char ch[21]; int x,y;
scanf("%s%d%d",ch,&x,&y);
if(ch[0]=='b') {
// printf("!%d %d\n",Fd_rt(x),Fd_rt(y));
if(Fd_rt(x)!=Fd_rt(y)) {printf("yes\n");Link(x,y);}
else printf("no\n");
}
else if(ch[0]=='p') {
splay(x);val[x]=y;P_up(x);
}
else {
// printf("!%d %d\n",Fd_rt(x),Fd_rt(y));
if(Fd_rt(x)!=Fd_rt(y)) {printf("impossible\n");continue;}
printf("%d\n",Sum(x,y));
}
}
return 0;
}

Link-Cut-Tree(1)的更多相关文章

  1. link cut tree 入门

    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...

  2. Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题

    A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...

  3. Link/cut Tree

    Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...

  4. 洛谷P3690 Link Cut Tree (模板)

    Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...

  5. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  6. bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门

    link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...

  7. P3690 【模板】Link Cut Tree (动态树)

    P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...

  8. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  9. [CodeForces - 614A] A - Link/Cut Tree

    A - Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, ...

  10. Link Cut Tree 总结

    Link-Cut-Tree Tags:数据结构 ##更好阅读体验:https://www.zybuluo.com/xzyxzy/note/1027479 一.概述 \(LCT\),动态树的一种,又可以 ...

随机推荐

  1. CSRF浅析

    概念 CSRF,Cross Site Request Forgery,跨站请求伪造. 为什么跨站的请求需要伪造? 因为浏览器实现了同源策略,这里可以将站和源视为同一个概念. 同源策略 The same ...

  2. Java/C++实现模板方法模式---数据库操作

    对数据库的操作一般包括连接.打开.使用.关闭等步骤,在数据库操作模板类中我们定义了connDB().openDB().useDB().closeDB()四个方法分别对应这四个步骤.对于不同类型的数据库 ...

  3. c++字符串替换

    #include <string> #include <iostream> using namespace std; string m_replace(string strSr ...

  4. leetcode-剑指 Offer II 012. 左右两边子数组的和相等

    题目描述: 给你一个整数数组 nums ,请计算数组的 中心下标 . 数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和. 如果中心下标位于数组最左端,那么左侧数之和视为 ...

  5. mysql基本操作1

    数据库的分类 --1.关系型数据库-----用"表"保存数据,相关数据存入一张表中   --2.非关系型数据库-----键值数据库-----对象数据库 ###主流关系型数据库-Or ...

  6. Input的校验表达式

    1.只是不能输入空格 <input type="text" onkeyup="this.value=this.value.replace(/^ +| +$/g,'' ...

  7. Docker的简介

    前言 Docker 是 PaaS 提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github 上, 基于go语言并遵从Apache2.0协议开源. 何为Docker? ...

  8. 测试开发【Mock平台】04实战:前后端项目初始化与登录鉴权实现

    [Mock平台]为系列测试开发教程,从0到1编码带你一步步使用Spring Boot 和 Antd React 框架完成搭建一个测试工具平台,希望作为一个实战项目能为你的测试开发学习有帮助. 一.后端 ...

  9. 用来创建用户docker registry认证的Secret

    集群环境:1.k8s用的是二进制方式安装2.操作系统是linux (centos)3.操作系统版本为 7.4/7.94.k8s的应用管理.node管理.pod管理等用rancher.k8s令牌以及ma ...

  10. 进程的概念及multiprocess模块的使用

    一.进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行实体:在 ...