正题

题目链接:https://www.luogu.com.cn/problem/P3348


题目大意

有\(n\)棵树开始只有一个编号为\(1\)的节点且为标记点。\(m\)次操作要求支持

  1. 在\(l\sim r\)的树中的标记点下面加入一个新的编号的节点
  2. 将\(l\sim r\)的树上的标记点改为\(x\)(如果没有节点\(x\)就不操作)
  3. 询问第\(x\)棵树上\(u\)点到\(v\)点的距离

\(1\leq n\leq 10^5,1\leq m\leq 2\times 10^5\)

保证询问合法


解题思路

保证询问合法的话我们其实第一个操作理解为对所有树都操作就可以了。主要是第二个操作,在线区间\(LCT\)看起来就很不可做,所以考虑离线。

对于一个操作\(1\ l\ r\ x\)它会对\(l-1\)和\(l\)的树造成的影响是再往后直到下一个\(1\)操作之间所有的节点都会被接到不同的点下面。但是显然暴力改接是不行的,我们可以考虑对于两个\(1\)操作之间的\(0\)操作建立一个虚点下面链接的所有这个区间新建的点,然后每次就改接一个虚点就好了。

然后需要注意的一些细节:因为根是固定的不能用\(split\),会破坏父子关系(好像在\(makeroot(1)\)回去可以,但是据说很慢?),所以要差分求到根节点的路径长度。还要求\(lca\),\(LCT\)上求\(lca\)的话就\(access\)了\(x\)再到\(y\)最后\(Splay\)的那个\(y\)就是\(lca\)了。

还有因为如果没有节点\(x\)就不操作,所以我们需要记录一下每个点拥有的树的区间然后取一个交集就好了。

时间复杂度\(O(n\log n)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct node{
int x,l,r,id;
}q[N],c[N];
int n,m,num,cnt,ct,qt;
int L[N],R[N],ans[N],at[N];
struct LCT{
int fa[N],t[N][2],siz[N],v[N];
bool Nroot(int x)
{return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}
bool Direct(int x)
{return t[fa[x]][1]==x;}
void PushUp(int x){
siz[x]=siz[t[x][0]]+siz[t[x][1]]+v[x];
return;
}
void Rotate(int x){
int y=fa[x],z=fa[y];
int xs=Direct(x),ys=Direct(y);
int w=t[x][xs^1];
if(Nroot(y))t[z][ys]=x;
t[x][xs^1]=y;t[y][xs]=w;
if(w)fa[w]=y;fa[y]=x;fa[x]=z;
PushUp(y);PushUp(x);return;
}
void Splay(int x){
while(Nroot(x)){
int y=fa[x];
if(!Nroot(y))Rotate(x);
else if(Direct(x)==Direct(y))
Rotate(y),Rotate(x);
else Rotate(x),Rotate(x);
}
return;
}
int Access(int x){
int y=0,px=x;
for(;x;y=x,x=fa[x])
Splay(x),t[x][1]=y,PushUp(x);
Splay(px);return y;
}
void Link(int x,int y)
{Splay(x);fa[x]=y;return;}
void Cut(int x)
{Access(x);fa[t[x][0]]=0;t[x][0]=0;PushUp(x);return;}
}T;
bool cmp(node x,node y)
{return x.x<y.x;}
int main()
{
scanf("%d%d",&n,&m);
L[1]=cnt=at[1]=1;R[1]=n;
T.Link(2,1);cnt=2;int last=2,num=1,aux=2;
for(int i=1;i<=m;i++){
int op,l,r,x;
scanf("%d%d%d",&op,&l,&r);
if(op==0){
++num;at[num]=++cnt;
T.v[cnt]=T.siz[cnt]=1;
T.Link(cnt,aux);
L[num]=l;R[num]=r;
}
else if(op==1){
scanf("%d",&x);
l=max(l,L[x]);r=min(r,R[x]);
if(l>r)continue;
++cnt;T.Link(cnt,aux);
c[++ct]=(node){l,cnt,at[x]};
c[++ct]=(node){r+1,cnt,aux,0};
aux=cnt;
}
else{
scanf("%d",&x);
q[++qt]=(node){l,at[r],at[x],qt};
}
}
sort(q+1,q+1+qt,cmp);
sort(c+1,c+1+ct,cmp);
for(int i=1,z=1;i<=qt;i++){
int sum=0;
while(z<=ct&&c[z].x<=q[i].x)
T.Cut(c[z].l),T.Link(c[z].l,c[z].r),z++;
T.Access(q[i].l);sum+=T.siz[q[i].l];
int lca=T.Access(q[i].r);sum+=T.siz[q[i].r];
T.Access(lca);sum-=2*T.siz[lca];
ans[q[i].id]=sum;
}
for(int i=1;i<=qt;i++)
printf("%d\n",ans[i]);
return 0;
}

P3348-[ZJOI2016]大森林【LCT】的更多相关文章

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

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

  2. [ZJOI2016]大森林(LCT)

    题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...

  3. P3348 [ZJOI2016]大森林

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

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

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

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

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

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

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

  7. bzoj 4573: [Zjoi2016]大森林 lct splay

    http://www.lydsy.com/JudgeOnline/problem.php?id=4573 http://blog.csdn.net/lych_cys/article/details/5 ...

  8. P3348 [ZJOI2016]大森林(Link-cut-tree)

    传送门 题解 题面大意: \(0.\)区间加节点 \(1.\)区间换根 \(2.\)单点询问距离 如果没有\(1\)操作,因为区间加节点都是加在下面,所以我们可以直接把\(n\)棵树压成一棵树,直接询 ...

  9. BZOJ4573:[ZJOI2016]大森林——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=4573 https://www.luogu.org/problemnew/show/P3348#sub ...

  10. [ZJOI2016]大森林

    Description: 小Y家里有一个大森林,里面有n棵树,编号从1到n 0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例 ...

随机推荐

  1. vlc播放器设置开机自动全屏播放网络视频流

    因工作需要,要用vlc视频播放器实现开机自动全屏播放某个网络视频流.百度了下,说的都很模糊,经过整理,设置方法如下: 一,添加视频流地址:rtsp://wowzaec2demo.streamlock. ...

  2. 设置一个元素的HTML内容

    问题 你需要一个元素中的HTML内容 方法 可以使用Element中的HTML设置方法具体如下: Element div = doc.select("div").first(); ...

  3. 关于Eclipse中使用Maven进行Install安装时候报错Perhaps you are running on a JRE rather than a JDK?解决办法

    所遇到的问题: 详情报错: 英文描述: [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3. ...

  4. linux————mysql————修改密码

    SET PASSWORD FOR 'root'@'localhost' = PASSWORD('输入新密码');

  5. Mybatis笔记(1)

    一.Mabits简介 1.1 原始JDBC的分析 问题 ①数据库连接创建.释放频繁造成系统资源浪费从而影响系统性能 ②sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大,s ...

  6. Oracle环境配置之山路十八弯

    Oracle数据库的安装 背景: 因为疫情原因,只能在家上网课,学习Oracle的时候需要安装数据库,但是!! 安装的时候出现了报错: 无法检查指定的位置是否位于 CFS 上. 出来这个基本无解,这个 ...

  7. 性能测试工具JMeter 基础(二)—— 主界面介绍

    主界面介绍 JMeter的主界面主要分为菜单导航栏.工具栏.计划树标签栏.内容栏 菜单导航栏:全部的功能的都包含在菜单栏中 工具栏:相当于菜单栏常用功能的快捷按钮 计划树标签栏:显示测试用例(计划)相 ...

  8. 比培训机构还详细的 Python 学习路线,你信吗 0^0

    前言 这其实是将自己写的文章进行一个总结分类,并不代表最佳学习路线 会不断更新这篇文章...没链接的文章正在编写ing...会不会哪天我的这个目录就出现在培训机构的目录上了... 目前实战比较少(要是 ...

  9. Python常见问题 - 写入数据到 excel 报 ValueError: invalid literal for int() with base 10 错误

    背景 在上写入数据到excel中,报了以下错误 出现原因 对于写入excel场景下出现该错误的话,很大概率是写入数据的单元格原本的数据格式有问题 解决方法 清理掉单元格的旧数据,然后再写入就可以了

  10. Delphi使用AcroPDF ActiveX显示PDF文件

    效果展示 调用方式 放入窗体即可使用,不想安装太多组件,可使用纯代码方式调用 interface ..... var AcroPDF: TAcroPDF; .... implementation .. ...