正题

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


题目大意

有nnn棵树开始只有一个编号为111的节点且为标记点。mmm次操作要求支持

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

1≤n≤105,1≤m≤2×1051\leq n\leq 10^5,1\leq m\leq 2\times 10^51≤n≤105,1≤m≤2×105
保证询问合法


解题思路

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

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

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

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

时间复杂度O(nlog⁡n)O(n\log n)O(nlogn)


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. [BZOJ4573][[Zjoi2016]大森林][LCT建虚点]

    [BZOJ4573][[Zjoi2016]大森林][LCT建虚点] 题意懒得写了.... 思路: 建LCT的时候我们可以引入虚点.对于所有的1操作,新建一个没有权值的虚点,然后对于0操作,可以把新建的 ...

  2. [ZJOI2016]大森林(LCT)

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

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

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

  4. [ZJOI2016]大森林

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

  5. bzoj 4573: [Zjoi2016]大森林

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

  6. [2019.3.20]BZOJ4573 [Zjoi2016]大森林

    发现一个重要的性质:由于不存在删点的操作,所以之后的加点并不会对之前的询问的答案造成影响. 所以我们可以先处理修改,再处理询问. 考虑从左到右扫描每一颗树,每次将前一棵树通过一些修改变为后一棵树. 发 ...

  7. BZOJ4573 : [Zjoi2016]大森林

    扫描线,从左到右依次处理每棵树. 用set按时间顺序维护影响了这棵树的所有操作,那么一个点的父亲就是它前面第一个操作1. 用Splay维护树的括号序列,那么两点间的距离就是括号数量减去匹配的括号个数. ...

  8. 「ZJOI2016」大森林 解题报告

    「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...

  9. bzoj 4573 大森林

    bzoj 4573 大森林 由于树上路径是唯一的,查询合法的两个点间路径长度显然与其他加点操作无关,所以可以离线处理,将所有的查询放在加点后. 这样我们可以对每棵树都在上颗树的基础上处理好形态后,处理 ...

  10. 3825. 逃离大森林

    3825. 逃离大森林 题目链接 #include <bits/stdc++.h> #define x first #define y second using namespace std ...

最新文章

  1. 什么是存储过程?什么是触发器?SQL中存储过程与触发器的区别是什么?
  2. django使用ckeditor富文本编辑器-转
  3. STM32系统时钟默认设置
  4. stm32 web ajax,STM32的WEB服务器怎么返回AJAX的JSON数据格式的?求教!
  5. c语言比较当前日期大小,C语言判断两个日期只差的方法
  6. asp.net core源码飘香:Configuration组件
  7. stack overflow--技术问答网站
  8. 基于Wi-Fi的室内定位在美团总部的实践和应用(上)
  9. 导航无限级菜单 java,Element NavMenu 无限级菜单
  10. java comparable接口_浅谈程序接口
  11. python tkinter进度条_在python tkinter中Canvas实现进度条显示的方法
  12. python正则表达式怎么用_python正则表达式的使用
  13. C++ 长字符串换行
  14. C++制作鼠标连点器
  15. 深度学习入门资料整理
  16. Guitar Pro 8win10最新版吉他学习 / 打谱 / 创作
  17. Spring ClassPathResource详解
  18. 爬虫返回乱码以及解决办法以及锟斤拷、ISO-8859-1转码、#、#x转码、unicode转码,gbk转码,ascii转码
  19. 知识图谱在应用过程中,主要面临哪些困难?
  20. C++ - PAT- L1-030. 一帮一(天梯赛决赛题目)

热门文章

  1. levedb 导入 mysql_LevelDB-初始篇
  2. linux怎么搜索特定文件夹,linux如何在特定文件夹中查找特定文件
  3. java8 垃圾 不同_【不同的Java垃圾回收器的比较】
  4. mockito mock void方法_使用 Junit + Mockito 实践单元测试!
  5. apk源码查看工具_如何查看Linux命令工具的源码?
  6. leetcode84. 柱状图中最大的矩形
  7. leetcode199. 二叉树的右视图(层序遍历03)
  8. 7-48 银行排队问题之单窗口“夹塞”版 (30 分)(思路和详解+map做法)来呀Baby!
  9. 文件的创建与读取 文件的数据添加
  10. java numberformat异常_Java NumberFormat格式化float类型的bug