传送门

题解

题面大意:

\(0.\)区间加节点

\(1.\)区间换根

\(2.\)单点询问距离

如果没有\(1\)操作,因为区间加节点都是加在下面,所以我们可以直接把\(n\)棵树压成一棵树,直接询问即可

有\(1\)操作怎么办?

上面挖掘了一点性质,

加节点加在下面,那么我们可以先把节点都加上去,再询问

那么把操作离线,

先按操作位置排序,再按操作排序(\(0,1\)先),再按时间排序

对于\(0,1\)操作都新建节点

\(0\)建实点

\(1\)建虚点

\(0\)操作的点将连向最后的\(1\)操作

默认每个\(1\)操作连向上一个操作(加点直接加在\(1\)下面)

现在唯一的问题即是\(1\)操作

我们想一下\(pos\)转移到\(pos+1\)

由于一些换根操作

树的形态会发生改变

假如一个换根操作\([l,r]\)

\(x\)换到\(y\)

\(l-1\),根是\(x\)

\(l\),根是\(y\)

那么改变的地方就是把在\(x->y\)操作之后接上\(x\)的点,全部接到\(y\)下面

一个一个挪肯定不行

所以需要一个虚点,挪的话只要挪这一个点

如果没有理解,可以想想,哪些点会连向这个虚点?

一定是时间在它之后的点

没换根之前,这些点都会连向\(x\)

那么问题就解决了..

Code

#include<bits/stdc++.h>

#define LL long long
#define RG register using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 500010;
int ch[N][2], val[N], sum[N], fa[N], tot;
bool isroot(int x) { return ch[fa[x]][0] != x && ch[fa[x]][1] != x; }
#define get(x) (ch[fa[x]][1] == x)
void pushup(int x) { sum[x] = sum[ch[x][0]] + sum[ch[x][1]] + val[x]; }
void rotate(int x) {
int y = fa[x], z = fa[y], k = get(x);
if (!isroot(y)) ch[z][get(y)] = x; fa[x] = z;
ch[y][k] = ch[x][k ^ 1]; fa[ch[x][k ^ 1]] = y;
ch[x][k ^ 1] = y; fa[y] = x;
pushup(y);
}
void splay(int x) {
while (!isroot(x)) {
int y = fa[x];
if (!isroot(y))
(get(x) ^ get(y)) ? rotate(x) : rotate(y);
rotate(x);
}
pushup(x);
}
int access(int x) {
int y = 0; for (; x; y = x, x = fa[x]) splay(x), ch[x][1] = y, pushup(x);
return y;
}
void link(int x, int y) { access(x); splay(x); fa[x] = y; }
void cut(int x) { access(x); splay(x); ch[x][0] = fa[ch[x][0]] = 0; pushup(x); }
void newnode(int x) { val[++tot] = x; sum[tot] = x; }
int L[N], R[N], id[N], len;
struct node {
int pos, op, x, y;
bool operator < (const node &z) const {
return pos == z.pos ? op < z.op : pos < z.pos;
}
}q[N];
int ans[N];
int query(int x, int y) {
int ans = 0, lca;
access(x), splay(x); ans += sum[x];
lca = access(y), splay(y), ans += sum[y];
access(lca), splay(lca), ans -= 2 * sum[lca];
return ans;
}
int main() {
int n, m, cnt = 1, last = 2, qs = 0;
read(n), read(m);
newnode(1); L[1] = 1, R[1] = n; id[1] = 1;
newnode(0); link(2, 1);
for (int i = 1; i <= m; i++) {
int op; read(op);
if (!op) {
int l, r;
read(l), read(r);
newnode(1);
L[++cnt] = l, R[cnt] = r, id[cnt] = tot;
q[++len] = (node) {1, i - m, tot, last};
}
else if (op == 1) {
int l, r, x;
read(l), read(r), read(x);
l = max(l, L[x]), r = min(r, R[x]);
if (l <= r) {
newnode(0); link(tot, last);
q[++len] = (node) {l, i - m, tot, id[x]};
q[++len] = (node) {r + 1, i - m, tot, last};
last = tot;
}
}
else {
int x, u, v;
read(x), read(u), read(v);
q[++len] = (node) {x, ++qs, id[u], id[v]};
}
}
sort(q + 1, q + len + 1);
int j = 1;
for (int i = 1; i <= n; i++)
while (i == q[j].pos && j <= len) {
if (q[j].op <= 0) cut(q[j].x), link(q[j].x, q[j].y);
else ans[q[j].op] = query(q[j].x, q[j].y);
j++;
}
for (int i = 1; i <= qs; i++) printf("%d\n", ans[i]);
return 0;
}

P3348 [ZJOI2016]大森林(Link-cut-tree)的更多相关文章

  1. [BJOI2014]大融合(Link Cut Tree)

    [BJOI2014]大融合(Link Cut Tree) 题面 给出一棵树,动态加边,动态查询通过每条边的简单路径数量. 分析 通过每条边的简单路径数量显然等于边两侧节点x,y子树大小的乘积. 我们知 ...

  2. P3348 [ZJOI2016]大森林

    \(\color{#0066ff}{ 题目描述 }\) 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点, ...

  3. ●洛谷P3348 [ZJOI2016]大森林

    题链: https://www.luogu.org/problemnew/show/P3348 题解: LCT,神题 首先有这么一个结论: 每次的1操作(改变生长点操作),一定只会会对连续的一段区间产 ...

  4. 洛谷P3348 [ZJOI2016]大森林 [LCT]

    传送门 刷了那么久水题之后终于有一题可以来写写博客了. 但是这题太神仙了我还没完全弄懂-- upd:写完博客之后似乎懂了. 思路 首先很容易想到\(O(n^2\log n)\)乘上\(O(\frac{ ...

  5. [NOI2014] 魔法森林 - Link Cut Tree

    [NOI2014] 魔法森林 Description 给定一张图,每条边 \(i\) 的权为 \((a_i,b_i)\), 求一条 \(1 \sim n\) 路径,最小化 \(\max_{i\in P ...

  6. P3348 [ZJOI2016]大森林(LCT)

    Luogu3348 BZOJ4573 LOJ2092 题解 对于每个\(1\)操作建一个虚点,以后的\(0\)操作都连在最近建好的虚点上.这样每次整体嫁接的时候,直接把这个虚点断掉它原来的父亲,再\( ...

  7. 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)

    洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不 ...

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

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

  9. Link Cut Tree学习笔记

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

随机推荐

  1. JQuery 对象和事件

    JQuery 对象和事件 一:JQuery 对象和 Dom 对象 在使用 JQuery 过程中,我们一般(也是绝大多数情况下,除非我们使用了第二个框架)只有两类对象,即:JQuery 对象和 Dom ...

  2. 友盟统计小白教程:创建应用,申请appkey

    上回书讲到,我们已经和一个靠谱的人选择一个靠谱的统计平台注册了一个帐号,下面就该创建一个应用了. 介绍一个基础知识: appkey:友盟识别app的唯一标识,目前友盟平台上超过500000款App,每 ...

  3. UVa 506 System Dependencies (细节问题)

    题意:输入几种指令,让你进行模拟操作,指令如下: DEPEND item1 item2 (item3 ...) 安装item1需要先安装item2(.item3……) INSTALL item1 安装 ...

  4. HTTP请求头和响应头总结

    1)请求(客户端->服务端[request])     GET(请求的方式) /books/java.html(请求的目标资源) HTTP/1.1(请求采用的协议和版本号)     Accept ...

  5. 使用Nmap攻击靶机和使用Wireshark进行嗅探、分析

    使用Nmap攻击靶机和使用Wireshark进行嗅探.分析 在上一次课中已经对Nmap的使用.原理已经做了很多学习,这次的课更多地针对Wireshark进行学习和使用. 使用192.168.200.1 ...

  6. 20155308 2016-2017-2 《Java程序设计》第8周学习总结

    20155308 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 第十四章 NIO与NIO2 NIO(New IO)-from JDK1.4 NIO2 -fr ...

  7. 自定义View--滚动View

    实现这么一个效果,一个布局中有一个View,那个View会随着我们手指的拖动而滑动,这种效果该如何实现?   我们第一反应应该是自定义一个DragView类继承View,然后重写onTouchEven ...

  8. Struts+Spring+Hibernate整合

    这段笔记三两年前写的,一直因为一些琐事,或者搞忘记了,没有发.今天偶然翻出了它,就和大家一起分享下吧. 1.导入jar包 Struts的jar包: Spring的jar包: Hibernate的jar ...

  9. Java Float类型 减法运算时精度丢失问题

    package test1; public class Test2 { /*** @param args*/public static void main(String[] args) {   Flo ...

  10. (转)JDBC模板类。

    Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式. JdbcTempl ...