版权声明:本文为博主原创文章,喜欢就点个赞吧 https://blog.csdn.net/Anxdada/article/details/81777558
模板题 - P3369
其中这道题的题解的第一篇讲解LCT异常详细, 可以通过这个来学习LCT, 另外再附上三篇详细博客, 基本上是讲解的最清楚的乐.
第一篇
第二篇
第三篇(最好的一篇)
模板题AC Code
const int maxn = 3e5 + 5;
int a[maxn];
struct node {
int fa, son[2], sz, val, lazy;
void init() {
sz = 1; lazy = 0;
fa = son[0] = son[1] = 0;
}
}t[maxn];
bool nroot(int x) {
return t[t[x].fa].son[0] == x || t[t[x].fa].son[1] == x;
}
void update(int x) {
t[x].val = a[x];
int l = t[x].son[0], r = t[x].son[1];
if(l) t[x].val ^= t[l].val;
if(r) t[x].val ^= t[r].val;
}
void pushdown(int x) {
if(t[x].lazy) {
t[x].lazy = 0;
swap(t[x].son[0], t[x].son[1]);
t[t[x].son[0]].lazy ^= 1;
t[t[x].son[1]].lazy ^= 1;
}
}
void rot(int x) {
int fa = t[x].fa, gfa = t[t[x].fa].fa;
int k = (x == t[fa].son[1]);
t[fa].son[k] = t[x].son[k^1];
if(nroot(fa)) t[gfa].son[fa == t[gfa].son[1]] = x;
if(t[x].son[k^1]) t[t[x].son[k^1]].fa = fa;
t[x].son[k^1] = fa;
t[fa].fa = x; t[x].fa = gfa;
update(fa);
}
int stk[maxn], top;
void splay(int x) {
top = 0; stk[++top] = x;
for(int i = x ; nroot(i) ; i = t[i].fa) {
stk[++top] = t[i].fa;
}
while(top) pushdown(stk[top--]);
for(int fa ; nroot(x) ; rot(x)) {
if(nroot(fa = t[x].fa))
rot((t[x].son[0] == x) ^ (t[fa].son[0] == fa) ? fa : x);
}
update(x);
}
int access(int x) {
int i;
for(i = 0 ; x ; x = t[i = x].fa) {
splay(x); t[x].son[1] = i; update(x);
}
return i;
}
int lca(int x, int y) {
access(x); return access(y);
}
void makeroot(int x){
access(x); splay(x); t[x].lazy ^= 1;
}
int findroot(int x) {
access(x); splay(x);
while(t[x].son[0]) pushdown(x), x = t[x].son[0];
return x;
}
void split(int x, int y) {
makeroot(x); access(y); splay(y);
}
void link(int x, int y) {
makeroot(x);
if(findroot(y) != x) t[x].fa = y;
}
void cut(int x, int y) {
makeroot(x);
if(findroot(y) == x && t[x].fa == y && !t[x].son[1]){
t[x].fa = t[y].son[0] = 0;
update(y);
}
}
int query(int x, int y) {
split(x, y);
return t[y].val;
}
void solve() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1 ; i <= n ; i ++) {
scanf("%d", a+i);
t[i].init(); t[i].val = a[i];
}
while(m--) {
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if (!op) printf("%d\n", query(x, y));
else if (op == 1) link(x, y);
else if (op == 2) cut(x, y);
else splay(x), a[x] = y;
}
}
这个由于太难了, 时间久了怕忘记一些东西的作用, 所以再附上解释版.
const int maxn = 300009;
int a[maxn];
struct node {
int fa, son[2], sz, val, lazy;
void init() {
sz = 1; lazy = 0;
fa = son[0] = son[1] = 0;
}
}t[maxn];
bool nroot(int x) { //判断节点是否为一个Splay的根(与普通Splay的区别1)
return t[t[x].fa].son[0] == x || t[t[x].fa].son[1] == x;
} //原理很简单,如果连的是轻边,他的父亲的儿子里没有它
void update(int x) { //更新信息
t[x].val = a[x];
int l = t[x].son[0], r = t[x].son[1];
if(l) t[x].val ^= t[l].val;
if(r) t[x].val ^= t[r].val;
}
void pushr(int x){
swap(t[x].son[0], t[x].son[1]);
r[x] ^= 1;
} //翻转操作(这里没有用到)
void pushdown(int x) { //判断并释放懒标记
if(t[x].lazy) {
t[x].lazy = 0;
swap(t[x].son[0], t[x].son[1]);
t[t[x].son[0]].lazy ^= 1;
t[t[x].son[1]].lazy ^= 1;
}
}
void rot(int x) { //一次旋转(左右旋都可进行)
int fa = t[x].fa, gfa = t[t[x].fa].fa;
int k = (x == t[fa].son[1]);
t[fa].son[k] = t[x].son[k^1];
if(nroot(fa)) t[gfa].son[fa == t[gfa].son[1]] = x;
//额外注意if(nroot(y))语句, 此处不判断会引起致命错误(普通Splay的区别2)
if(t[x].son[k^1]) t[t[x].son[k^1]].fa = fa;
t[x].son[k^1] = fa;
t[fa].fa = x; t[x].fa = gfa;
update(fa);
}
int stk[maxn], top;
void splay(int x) { //只传了一个参数,因为所有操作的目标都是该Splay的根(与普通Splay的区别3)
top = 0; stk[++top] = x;
for(int i = x ; nroot(i) ; i = t[i].fa) {
stk[++top] = t[i].fa;
}
while(top) pushdown(stk[top--]); // 一路释放懒人标记
//st为栈,暂存当前点到根的整条路径,pushdown时一定要从上往下放标记(与普通Splay的区别4)
for(int fa ; nroot(x) ; rot(x)) {
if(nroot(fa = t[x].fa))
rot((t[x].son[0] == x) ^ (t[fa].son[0] == fa) ? fa : x);
}
update(x);
}
int access(int x) { // 访问
int i;
for(i = 0 ; x ; x = t[i = x].fa) {
splay(x); t[x].son[1] = i; update(x);
}
return i; // 返回最后一次修改右孩子的点.
}
int lca(int x, int y) {
access(x); return access(y);
}
void makeroot(int x) { //换根
access(x); splay(x); t[x].lazy ^= 1;
}
int findroot(int x) { //找根(在真实的树中的)
access(x); splay(x);
while(t[x].son[0]) pushdown(x), x = t[x].son[0];
return x;
}
void split(int x, int y) { //提取路径(以y作为根)
makeroot(x); access(y); splay(y);
}
void link(int x, int y) { //连边
makeroot(x);
if(findroot(y) != x) t[x].fa = y;
}
void cut(int x, int y) { //断边
makeroot(x);
if(findroot(y) == x && t[x].fa == y && !t[x].son[1]){
t[x].fa = t[y].son[0] = 0;
update(y);
}
}
int query(int x, int y) {
split(x, y);
return t[y].val;
}
void solve() {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1 ; i <= n ; i ++) {
scanf("%d", a+i);
t[i].init(); t[i].val = a[i];
}
while(m--){
int op, x, y;
scanf("%d%d%d", &op, &x, &y);
if (!op) printf("%d\n", query(x, y));
else if (op == 1) link(x, y);
else if (op == 2) cut(x, y);
else splay(x), a[x] = y;
}
}