lct是一种动态树,用来维护一些动态加边删边的操作的东西.他主要用到几个操作,其实这个算法和树链刨分有点像,但是不能用线段树简单维护,所以我们要用多棵平衡树来维护树上的一个个子树,然后就进行一些很秀的操作.详情见这个博客:FlashHu

这个博客讲的是真的好,特别适合新手看,而且特别细节,(特别带劲).现在我就可以上代码:

模板:

#include <iostream>
#include <cassert>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
#define duke(i, a, n) for (register int i = a; i <= n; i++)
#define lv(i, a, n) for (register int i = a; i >= n; i--)
#define clean(a) memset(a, 0, sizeof(a))
const int INF = << ;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x) {
char c;
bool op = ;
while (c = getchar(), c < '' || c > '')
if (c == '-')
op = ;
x = c - '';
while (c = getchar(), c >= '' && c <= '') x = x * + c - '';
if (op)
x = -x;
}
template <class T>
void write(T x) {
if (x < )
putchar('-'), x = -x;
if (x >= )
write(x / );
putchar('' + x % );
}
const int N = ;
struct node {
int fa, ch[], rev, v, s;
} a[N];
int st[N];
#define O(a) cout << #a << " " << a << endl;
int n, m;
bool isroot(int x) { return !(a[a[x].fa].ch[] == x || a[a[x].fa].ch[] == x); }
void pushr(int x) {
swap(a[x].ch[], a[x].ch[]);
a[x].rev ^= ;
}
void push_down(int k) {
if (a[k].rev) {
if (a[k].ch[])
pushr(a[k].ch[]);
if (a[k].ch[])
pushr(a[k].ch[]);
a[k].rev ^= ;
}
}
void push_up(int x) { a[x].s = a[a[x].ch[]].s ^ a[a[x].ch[]].s ^ a[x].v; }
void connect(int x, int fa, int son) {
a[x].fa = fa;
a[fa].ch[son] = x;
}
int iden(int x) { return a[a[x].fa].ch[] == x ? : ; }
void rotate(int x) {
int y = a[x].fa;
int mroot = a[y].fa;
int mrootson = iden(y);
int yson = iden(x);
int b = a[x].ch[yson ^ ];
if (!isroot(y)) {
a[mroot].ch[mrootson] = x;
}
a[x].fa = mroot;
connect(b, y, yson);
connect(y, x, yson ^ );
push_up(y);
push_up(x);
}
void splay(int x) {
int top = ;int i;
st[++top] = x;
for (i = x; !isroot(i); i = a[i].fa) {
st[++top] = a[i].fa;
}
for (int i = top; i >= ; i--) {
push_down(st[i]);
}
while (!isroot(x)) {
int y = a[x].fa;
if (isroot(y)) {
rotate(x);
} else if (iden(x) == iden(y)) {
rotate(y);
rotate(x);
} else {
rotate(x);
rotate(x);
}
}
push_up(x);
}
void access(int x) {
int t = ;
while (x) {
splay(x);
a[x].ch[] = t;
push_up(x);
t = x;
x = a[x].fa;
}
}
void make_root(int x) {
access(x);
splay(x);
// a[a[x].ch[0]].rev ^= 1;
// a[a[x].ch[1]].rev ^= 1;
pushr(x);
// swap(a[x].ch[0],a[x].ch[1]);
// push_down(x);
}
void split(int x, int y) {
// if (x <= n && y <= n) {
make_root(x);
access(y);
splay(y);
// }
}
int findroot(int x) {
access(x);
splay(x);
push_down(x);
while (a[x].ch[]){
push_down(a[x].ch[]);
x = a[x].ch[];
}
return x;
}
void link(int x, int y) {
make_root(x);
int t = findroot(y);
assert(t);
if ( t != x)
a[x].fa = y;
}
void cut(int x, int y) {
make_root(x);
int t = findroot(y);
assert(t);
if (t == x && a[x].fa == y && !a[x].ch[]) {
a[x].fa = a[y].ch[] = ;
push_up(y);
}
}
int main() {
// freopen("in.in","r",stdin);
int x, y, typ;
read(n);
read(m);
duke(i, , n) { read(a[i].v); push_up(i); }
int oup = ;
duke(mi,,m){
read(typ);
read(x);
read(y);
if (typ == ) {
split(x, y);
printf("%d\n", a[y].s);
++oup; } else if (typ == ) {
link(x, y);
} else if (typ == ) {
cut(x, y);
} else {
splay(x);
a[x].v = y;
}
// cout<<a[1].ch[0]<<" "<<a[1].ch[1]<<" "<<a[1].fa<<" "<<a[1].v<<" "<<a[1].s<<endl;
}
return ;
}

魔法森林:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;i++)
#define lv(i,a,n) for(register int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = << ;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
#define min2(x,y) if(x>y)x=y;
const int N = 2e5 + ;
const int P = ;
struct node
{
int fa,ch[],rev,v,mx;
}a[N];
int st[N],n,m;
struct edge
{
int u,v,a,b;
bool operator < (const edge &oth) const
{
return a < oth.a;
}
void getin()
{
read(u);read(v);
read(a);read(b);
u |= P;v |= P;
}
}e[ * N];
bool isroot(int x)
{
return a[a[x].fa].ch[] != x && a[a[x].fa].ch[] != x;
}
void pushr(int x)
{
swap(a[x].ch[],a[x].ch[]);
a[x].rev ^= ;
}
void push_down(int x)
{
if(a[x].rev)
{
// if(a[a[x].ch[0]].rev) pushr(a[x].ch[0]);
// if(a[a[x].ch[1]].rev) pushr(a[x].ch[1]);
swap(a[x].ch[],a[x].ch[]);
a[a[x].ch[]].rev ^= ;
a[a[x].ch[]].rev ^= ;
a[x].rev ^= ;
}
}
void push_up(int x)
{
a[x].mx = x;
if(e[a[x].mx].b < e[a[a[x].ch[]].mx].b) a[x].mx = a[a[x].ch[]].mx;
if(e[a[x].mx].b < e[a[a[x].ch[]].mx].b) a[x].mx = a[a[x].ch[]].mx;
}
int iden(int x)
{
return a[a[x].fa].ch[] == x ? : ;
}
void connect(int x,int fa,int son)
{
a[x].fa = fa;
a[fa].ch[son] = x;
}
void rotate(int x)
{
int y = a[x].fa;
int mroot = a[y].fa;
int mrootson = iden(y);
int yson = iden(x);
int b = a[x].ch[yson ^ ];
if(!isroot(y))
{
a[mroot].ch[mrootson] = x;
}
a[x].fa = mroot;
connect(y,x,yson ^ );
connect(b,y,yson);
push_up(y);
// update(x);
}
void splay(int x)
{
int top = ,i;
st[++top] = x;
for(i = x;!isroot(i);i = a[i].fa)
{
st[++top] = a[i].fa;
}
push_down(a[i].fa);
for(int i = top;i;i--)
{
push_down(st[i]);
}
while(!isroot(x))
{
int y = a[x].fa;
if(isroot(y)) rotate(x);
else if(iden(x) == iden(y))
{
rotate(y);rotate(x);
}
else
{
rotate(x);rotate(x);
}
}
push_up(x);
}
void access(int x)
{
int t = ;
while(x)
{
splay(x);
a[x].ch[] = t;
push_up(x);
t = x;
x = a[x].fa;
}
}
void makeroot(int x)
{
access(x);
splay(x);
a[x].rev ^= ;
}
int findroot(int x)
{
access(x);
splay(x);
while(a[x].ch[])
x = a[x].ch[];
return x;
}
void link(int x)
{
int y = e[x].u,z = e[x].v;
makeroot(z);
a[a[z].fa = x].fa = y;
// a[x].fa = y;
}
void cut(int x)
{
access(e[x].v);
splay(x);
a[x].ch[] = a[x].ch[] = a[a[x].ch[]].fa = a[a[x].ch[]].fa = ;
push_up(x);
}
int main()
{
// freopen("2387.in","r",stdin);
int ans = INF;
read(n);read(m);
duke(i,,m)
{
e[i].getin();
}
sort(e + ,e + m + );
int y,z;
duke(i,,m)
{
if((y = e[i].u) == (z = e[i].v)) continue;
makeroot(y);
if(y != findroot(z)) link(i);
else if(e[i].b < e[a[z].mx].b)
{
cut(a[z].mx);
link(i);
}
makeroot( | P);
if(( | P) == findroot(n | P))
ans = min(ans,e[i].a + e[a[n | P].mx].b);
}
printf("%d\n",ans == INF ? - : ans);
return ;
}

弹飞绵羊:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<vector>
#include<complex>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
#define mp make_pair
#define cp complex<db>
#define enter puts("")
const long long INF = 1LL << ;
const double eps = 1e-;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
struct node
{
int ch[],siz,fa;
}a[];
int n,m;
int iden(int x)
{
return a[a[x].fa].ch[] == x ? : ;
}
void connect(int x,int fa,int son)
{
a[x].fa = fa;
a[fa].ch[son] = x;
}
bool isroot(int x)
{
return a[a[x].fa].ch[] != x && a[a[x].fa].ch[] != x;
}
void push_up(int x)
{
a[x].siz = a[a[x].ch[]].siz + a[a[x].ch[]].siz + ;
}
/*void pushr(int x)
{
swap(a[x].ch[0],a[x].ch[1]);
a[x].rev ^= 1;
}
void push_down(int x)
{
if(a[x].rev)
{
if(a[x].ch[0]) pushr(a[x].ch[0]);
if(a[x].ch[1]) pushr(a[x].ch[1]);
a[x].rev ^= 1;
}
}*/
void rotate(int x)
{
int y = a[x].fa;
int mroot = a[y].fa;
int mrootson = iden(y);
int yson =iden(x);
int b = a[x].ch[yson ^ ];
if(!isroot(y))
{
a[mroot].ch[mrootson] = x;
}
a[x].fa = mroot;
connect(b,y,yson);
connect(y,x,yson ^ );
push_up(y);
}
/*inline bool isroot(int x){
return a[a[x].fa].ch[0]==x||a[a[x].fa].ch[1]==x;
}
void rotate(int x){
int y=a[x].fa,z=a[y].fa,k=a[y].ch[1]==x,w=a[x].ch[!k];
if(isroot(y))a[z].ch[a[z].ch[1]==y] = x;a[x].ch[!k]=y;a[y].ch[k]=w;
if(w)a[w].fa=y;a[y].fa=x;a[x].fa=z;
push_up(y);
}*/
void splay(int x)
{
while(!isroot(x))
{
int y = a[x].fa;
if(isroot(y)) rotate(x);
else if(iden(x) == iden(y))
{
rotate(y);rotate(x);
}
else
{
rotate(x);rotate(x);
}
}
push_up(x);
}
/*void splay(int x){
int y,z;
while(isroot(x)){
y=a[x].fa;z=a[y].fa;
cout<<x<<endl;
if(isroot(y))
rotate((a[y].ch[0]==x)^(a[z].ch[0]==y)?y:x);
rotate(x);
}
push_up(x);
}*/
void access(int x)
{
int t = ;
while(x)
{
splay(x);
a[x].ch[] = t;
t = x;
push_up(x);
x = a[x].fa;
}
}
int ch,j,k;
int main()
{
// freopen("3203.in","r",stdin);
read(n);
duke(i,,n)
{
a[i].siz = ;
read(k);
if(i + k <= n)
a[i].fa = i + k;
}
read(m);
while(m--)
{
read(ch);
if(ch == )
{
read(j);j++;
access(j);splay(j);
printf("%d\n",a[j].siz);
}
else
{
read(j);read(k); ++j;
access(j);splay(j);
a[j].ch[] = a[a[j].ch[]].fa = ;
if(j + k <= n) a[j].fa = j + k;
push_up(j);
}
}
return ;
}
/*int main()
{
freopen("3203.in","r",stdin);
register char ch;
int n,m,j,k;
read(n);
for(j=1;j<=n;++j){
a[j].siz=1;
read(k);
if(j+k<=n)a[j].fa=j+k;//如果弹飞了就不连边
}
read(m);
int op = 0;
while(m--){
read(op);
if(op&1){
read(j);++j;
access(j);splay(j);//直接查询
printf("%d\n",a[j].siz);
}
else{
read(j);read(k);++j;
access(j);splay(j);
a[j].ch[0]=a[a[j].ch[0]].fa=0;//直接断边
if(j+k<=n)a[j].fa=j+k;//直接连边
push_
up(j);
}
}
return 0;
}*/

洞穴勘测:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(register int i = a;i <= n;i++)
#define lv(i,a,n) for(register int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = << ;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
char c;
bool op = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') op = ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(op) x = -x;
}
template <class T>
void write(T x)
{
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
}
struct node
{
int fa,ch[],rev;
}a[];
int n,m,st[];
bool isroot(int x)
{
return a[a[x].fa].ch[] != x && a[a[x].fa].ch[] != x;
}
void push_down(int k)
{
if(a[k].rev)
{
int l = a[k].ch[];
int r = a[k].ch[];
a[k].rev ^= ;
a[l].rev ^= ;
a[r].rev ^= ;
swap(a[k].ch[],a[k].ch[]);
}
}
int iden(int x)
{
return a[a[x].fa].ch[] == x ? : ;
}
void connect(int x,int f,int son)
{
a[x].fa = f;
a[f].ch[son] = x;
}
void rotate(int x)
{
int y = a[x].fa;
int mroot = a[y].fa;
int mrootson = iden(y);
int yson = iden(x);
int b = a[x].ch[yson ^ ];
if(!isroot(y))
{
a[mroot].ch[mrootson] = x;
}
a[x].fa = mroot;
connect(b,y,yson);
connect(y,x,yson ^ );
}
void splay(int x)
{
int top = ;
st[++top] = x;
for(int i = x;!isroot(i);i = a[i].fa)
{
st[++top] = a[i].fa;
// cout<<"gg"<<endl;
}
// cout<<"out"<<endl;
for(int i = top;i;i--)
push_down(st[i]);
while(!isroot(x))
{
int y = a[x].fa;
if(isroot(y)) rotate(x);
else if(iden(x) == iden(y))
{
rotate(y);rotate(x);
}
else
{
rotate(x);rotate(x);
}
// cout<<"233"<<endl;
}
}
void access(int x)
{
int t = ;
while(x)
{
splay(x);
a[x].ch[] = t;
t = x;
x = a[x].fa;
}
}
void rever(int x)
{
access(x);
splay(x);
a[x].rev ^= ;
}
void link(int x,int y)
{
rever(x);a[x].fa = y;
splay(x);
// cout<<x<<" "<<y<<endl;
}
void cut(int x,int y)
{
rever(x);
access(y);
splay(y);
a[y].ch[] = a[x].fa = ;
}
int find(int x)
{
// cout<<x<<endl;
access(x);//cout<<"yes"<<endl;
splay(x);
int y = x;
//cout<<"!!!"<<y<<endl;
while(a[y].ch[])
y = a[y].ch[];
// cout<<y<<endl;
return y;
}
int main()
{
// freopen("2147.in","r",stdin);
char ch[];
int x,y;
read(n);read(m);
duke(i,,m)
{
scanf("%s",ch);
read(x);read(y);
if(ch[] == 'C') link(x,y);
else if(ch[] == 'D') cut(x,y);
else
{
if(find(x) == find(y)) printf("Yes\n");
else
printf("No\n");
}
}
return ;
}

LCT教程的更多相关文章

  1. Link-Cut Tree(LCT) 教程

    目录 前置知识 介绍 Access FindRoot MakeRoot Split Link Cut 关于Splay中操作的一点说明: 模板 前置知识 请先对树链剖分和Splay有所了解.LCT基于树 ...

  2. LCT 模板及套路总结

    这一个月貌似已经考了无数次\(LCT\)了..... 保险起见还是来一发总结吧..... A. LCT 模板 \(LCT\) 是由大名鼎鼎的 \(Tarjan\) 老爷发明的. 主要是用来维护树上路径 ...

  3. [洛谷日报第62期]Splay简易教程 (转载)

    本文发布于洛谷日报,特约作者:tiger0132 原地址 分割线下为copy的内容 [洛谷日报第62期]Splay简易教程 洛谷科技 18-10-0223:31 简介 二叉排序树(Binary Sor ...

  4. OI知识点|NOIP考点|省选考点|教程与学习笔记合集

    点亮技能树行动-- 本篇blog按照分类将网上写的OI知识点归纳了一下,然后会附上蒟蒻我的学习笔记或者是我认为写的不错的专题博客qwqwqwq(好吧,其实已经咕咕咕了...) 基础算法 贪心 枚举 分 ...

  5. Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求

    上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...

  6. Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数

    上一篇:Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数 之前介绍了简单的路由以及传参,这篇文章我们将要学习复杂一些的路由以及传递其他附加参数.一个好的路由系统可以使我们 ...

  7. Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数

    上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...

  8. Angular2入门系列教程4-服务

    上一篇文章 Angular2入门系列教程-多个组件,主从关系 在编程中,我们通常会将数据提供单独分离出来,以免在编写程序的过程中反复复制粘贴数据请求的代码 Angular2中提供了依赖注入的概念,使得 ...

  9. Angular2入门系列教程1-使用Angular-cli搭建Angular2开发环境

    一直在学Angular2,百忙之中抽点时间来写个简单的教程. 2016年是前端飞速发展的一年,前端越来越形成了(web component)组件化的编程模式:以前Jquery通吃一切的田园时代一去不复 ...

随机推荐

  1. 并发和多线程(三)--并发容器J.U.C和lock简介

    AQS: 是AbstractQueuedSynchronizer的简称,JUC的核心 底层是sync queue双向链表,还可能有condition queue单向链表,使用Node实现FIFO队列, ...

  2. 用meta name="renderer" content="webkit|ie-comp|ie-stand"来切换360双核安全浏览器的极速模式和兼容模式

    以下信息摘自360官方网站: 浏览模式:极速模式.兼容模式及IE9高速模式是360浏览器显示网页时使用的三种模式:极速模式表示极速模式兼容模式表示兼容模式IE9IE10模式表示IE9/IE10模式(仅 ...

  3. SAS,SATA普及文档

    目前所能见到的硬盘接口类型主要有IDE.SATA.SCSI.SAS.FC等等. IDE是俗称的并口,SATA是俗称的串口,这两种硬盘是个人电脑和低端服务器常见的硬盘.SCSI是"小型计算机系 ...

  4. 剑指offer---最小的K个数

    题目:最小的K个数 要求:输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. class Solution { public: ...

  5. python爬虫21 | 对于b站这样的滑动验证码,不好意思,照样自动识别

    今天 要来说说滑动验证码了 大家应该都很熟悉 点击滑块然后移动到图片缺口进行验证 现在越来越多的网站使用这样的验证方式 为的是增加验证码识别的难度 那么 对于这种验证码 应该怎么破呢 接下来就是 学习 ...

  6. Python-组合数据类型

    集合类型及操作 >集合类型定义 集合是多个元素的无序组合 -集合类型与数学中的集合概念一致 -集合元素之间无序,每个元素唯一,不存在相同元素 -集合元素不可更改,不能是可变数据类型 -集合用大括 ...

  7. MySQL Connector/Python 接口 (二)

    连接数据库 本文参见这里,示例如何连接MySQL 数据库. import mysql.connector from mysql.connector import errorcode # 连接数据库需要 ...

  8. 多校1007 Naive Operations

    >>点击进入原题测试<< 思路:好像是第一次这么印象深刻的写线段树,说实话,这个题确实很有意思,值得学习. 看了大神讲解视频,但是自己写的还是超时了. 参考来自 https:/ ...

  9. Spring 使用注解注入 学习(四)

    <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...

  10. Spring security 5 Authorize Configuration

    1. Spring Security 核心请求,认证配置类 WebSecurityConfigurerAdapter protected void configure(HttpSecurity htt ...