Description

小Y家里有一个大森林,里面有n棵树,编号从1到n。一开始这些树都只是树苗,只有一个节点,标号为1。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。小Y掌握了一种魔法,能让第l棵树到第r棵树的生长节点长出一个子节点。同时她还能修改第l棵树到第r棵树的生长节点。她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢?

Input

第一行包含 2 个正整数 n,m,共有 n 棵树和 m 个操作。接下来 m 行,每行包含若干非负整数表示一个操作,操作格式为:

0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例如,第一个 0 号操作产生的子节点标号为 2), l 到 r 之间的树长出的节点标号都相同。保证 1≤l≤r≤n 。

1 l r x 表示将第 l 棵树到第 r 棵树的生长节点改到标号为 x 的节点。对于 i (l≤i≤r)这棵树,如果标号 x的点不在其中,那么这个操作对该树不产生影响。保证 1≤l≤r≤n , x 不超过当前所有树中节点最大的标号。

2 x u v 询问第 x 棵树中节点 u 到节点 v 点的距离,也就是在第 x 棵树中从节点 u 和节点 v 的最短路上边的数量。保证1≤x≤n,这棵树中节点 u 和节点 v 存在。N<=105,M<=2*105

Output

输出包括若干行,按顺序对于每个小Y的询问输出答案

Sample Input

5 5

0 1 5

1 2 4 2

0 1 4

2 1 1 3

2 2 1 3

Sample Output

1

2

Solution

很巧妙的一道题目

这道题确实是LCT加“虚点”,但不要想复杂了,这个虚点跟虚树没半毛钱关系,只是这道题YY出来的一个东东

首先明白对于同一棵树,询问的操作永远可以放在修改操作之后,因为树的边只会增加,不会减少或变更。所以对于一棵树,直接考虑它的最终状态,然后处理询问

考虑只建一棵树,想办法在遍历的过程中快速从前面一棵树的形态变成接下来一棵树的形态

发现,如果先让所有的长出来的节点接在第一个生长节点(就是根)上,那么如果中间变更了生长节点,可以直接把在变更之后生长出的节点全部换根,变成新的生长节点的儿子。这个正好是新的形态。而对于 \(r\) 之后的,也就是没有变这个生长节点的树们,可以直接把换根过去的节点再换回来就变成应该的状态了

所以YY出了一个虚点,实际上就是没有点权的点

这个点可以用来当作它出现之后生长出的节点的根,换根的时候,直接带上这个虚点一起换,这样就只要改变两条边,就只是常数复杂度了

然后开始建最开始的树

对于每次长节点,就是在最近一次出现的虚点下加一个点,点权为1

对于每次有要更改节点的操作,暂时不进行更改(因为有个 \(l\) 到 \(r\) 的范围嘛),只是在上一个虚点之下再建一个虚点,之后的实点都加在这个新的虚点之下,保证换根的优秀复杂度

于是就可以离线了,输入操作的时候把初始树建好,并且对于每个更换节点的操作拆成两个操作,一个换根过去,一个换根回来

扫一遍就做完了

巧妙

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10,MAXM=200000+10,inf=0x3f3f3f3f;
int n,m,L[MAXM],R[MAXM],realcnt,nowaux,size,pt[MAXM+MAXN],pcnt,ans[MAXM],anscnt;
struct data{
int opt,ps,u,v;
inline bool operator < (const data &A) const {
return ps<A.ps||ps==A.ps&&opt<A.opt;
};
};
data p[MAXM<<1];
#define lc(x) ch[(x)][0]
#define rc(x) ch[(x)][1]
struct LCT{
int ch[MAXN+MAXM][2],fa[MAXN+MAXM],rev[MAXN+MAXM],sum[MAXN+MAXM],val[MAXN+MAXM],stack[MAXN+MAXM],cnt;
inline bool nroot(int x)
{
return lc(fa[x])==x||rc(fa[x])==x;
}
inline void reverse(int x)
{
std::swap(lc(x),rc(x));
rev[x]^=1;
}
inline void pushup(int x)
{
sum[x]=sum[lc(x)]+sum[rc(x)]+val[x];
}
inline void pushdown(int x)
{
if(rev[x])
{
if(lc(x))reverse(lc(x));
if(rc(x))reverse(rc(x));
rev[x]=0;
}
}
inline void rotate(int x)
{
int f=fa[x],p=fa[f],c=(rc(f)==x);
if(nroot(f))ch[p][rc(p)==f]=x;
fa[ch[f][c]=ch[x][c^1]]=f;
fa[ch[x][c^1]=f]=x;
fa[x]=p;
pushup(f);
pushup(x);
}
inline void splay(int x)
{
cnt=0;
stack[++cnt]=x;
for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
while(cnt)pushdown(stack[cnt--]);
for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
pushup(x);
}
inline int access(int x)
{
int y=0;
for(;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x);
return y;
}
inline void link(int x,int y)
{
splay(x);fa[x]=y;
}
inline void cut(int x)
{
access(x);splay(x);lc(x)=fa[lc(x)]=0;pushup(x);
}
};
LCT T;
#undef lc
#undef rc
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
read(n);read(m);
pt[++realcnt]=++size;
nowaux=++size;
T.val[1]=1;
L[1]=1;R[1]=n;
T.link(nowaux,1);
for(register int i=1;i<=m;++i)
{
int opt;
read(opt);
if(opt==0)
{
int l,r;
read(l);read(r);
pt[++realcnt]=++size;
L[realcnt]=l,R[realcnt]=r;
T.val[size]=1;
T.link(size,nowaux);
}
if(opt==1)
{
int l,r,x;
read(l);read(r);read(x);
chkmax(l,L[x]);chkmin(r,R[x]);
if(l>r)continue;
T.link(++size,nowaux);
p[++pcnt]=(data){i-m,l,size,pt[x]};
p[++pcnt]=(data){i-m,r+1,size,nowaux};
nowaux=size;
}
if(opt==2)
{
int x,u,v;
read(x);read(u);read(v);
p[++pcnt]=(data){++anscnt,x,pt[u],pt[v]};
}
}
std::sort(p+1,p+pcnt+1);
for(register int i=1;i<=pcnt;++i)
if(p[i].opt>0)
{
int res=0,lca;
T.access(p[i].u);T.splay(p[i].u);res+=T.sum[p[i].u];
lca=T.access(p[i].v);T.splay(p[i].v);res+=T.sum[p[i].v];
T.access(lca);T.splay(lca);res-=(T.sum[lca]<<1);
ans[p[i].opt]=res;
}
else T.cut(p[i].u),T.link(p[i].u,p[i].v);
for(register int i=1;i<=anscnt;++i)write(ans[i],'\n');
return 0;
}

【刷题】BZOJ 4573 [Zjoi2016]大森林的更多相关文章

  1. bzoj 4573: [Zjoi2016]大森林

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

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

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

  3. [ZJOI2016]大森林(LCT)

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

  4. [ZJOI2016]大森林

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

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

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

  6. 【LuoguP3348】[ZJOI2016]大森林

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

  7. P3348 [ZJOI2016]大森林

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

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

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

  9. [BZOJ4573][ZJOI2016]大♂森林

    bzoj luogu uoj sol \(orz\ \ HJT\ \ dalao\)教会我做这道题. 考虑每两个相邻位置的树的差异. 对于一个1操作(更换生长节点),假设区间是\([l,r]\),那么 ...

随机推荐

  1. ffmpeg 踩坑实录 近期使用总结(三)

    一.背景介绍 将ffmpeg运用到项目上已经有一段时间了,趁现在有空赶紧记下来. 二.技术点总结    2.1 实现方式 项目里面主要运用的形式是,在java端,调用操作系统的方法,并执行切片命令. ...

  2. python爬取斗图网中的 “最新套图”和“最新表情”

    1.分析斗图网 斗图网地址:http://www.doutula.com 网站的顶部有这两个部分: 先分析“最新套图” 发现地址栏变成了这个链接,我们在点击第二页 可见,每一页的地址栏只有后面的pag ...

  3. 《Angular4从入门到实战》学习笔记

    <Angular4从入门到实战>学习笔记 腾讯课堂:米斯特吴 视频讲座 二〇一九年二月十三日星期三14时14分 What Is Angular?(简介) 前端最流行的主流JavaScrip ...

  4. html的背景样式图片

    背景图片 如果背景图片小于当前的div的情况下 默认的是将平铺充满元素 background-image 设置背景图片. background-repeat 设置是否及如何重复背景图片. repeat ...

  5. 回归Qt——写在Qt5.10发布之日

    今天偶然看到一条关于Qt5.10发布的消息,发现Qt经历了诺基亚风波之后发展得依然良好,感到很欣慰.回头看上次关注Qt技术还是2011年,那时候用Qt4.7做一个小项目,对于一个写Win32界面和MF ...

  6. 如何计算FOB价格

    FOB价格是国际贸易术语常有的一种算法,针对不同的对象,FOB价格也有不一样的算法.对于做外贸生意的朋友,需要了解FOB价格以及各项费用名称,以及如何计算FOB价格. FOB价格是国际FOB价格语常有 ...

  7. 机器学习笔记(4)Logistic回归

    模型介绍 对于分类问题,其得到的结果值是离散的,所以通常情况下,不适合使用线性回归方法进行模拟. 所以提出Logistic回归模型. 其假设函数如下: \[ h_θ(x)=g(θ^Tx) \] 函数g ...

  8. Beta版冲刺前准备

    [团队概要] 团队项目名:小葵日记 团队名:日不落战队 队员及角色: 队员 角色 备注 安琪 前端工程师 队长 佳莹 前端工程师 智慧 后端工程师 章鹏 后端工程师 语恳 UI设计师 炜坤 前端工程师 ...

  9. 设计模式--Restful笔记(一)

    一.REST基础概念 首先REST是 Representational State Transfer 的缩写,如果一个架构符合REST原则,它就是RESTful架构. 在REST中的一切都被认为是一种 ...

  10. QThread安全的结束线程

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QThread安全的结束线程     本文地址:http://techieliang.com/ ...