bzoj

luogu

uoj

sol

\(orz\ \ HJT\ \ dalao\)教会我做这道题。

考虑每两个相邻位置的树的差异。

对于一个1操作(更换生长节点),假设区间是\([l,r]\),那么第\(l-1\)棵树和第\(l\)棵数就会产生一定的差异,具体来说,假设在这之后没有1操作了,那么所有应该在第\(l-1\)棵树中接到原生长节点下面的点都在第\(l\)棵树中被接到了新的生长节点的下面。

我们考虑怎么快速实现这个操作。很显然,我们只要把修改了生长节点后新长出来的点打个包,然后\(cut\)再\(link\)一下就好了。

如果是一棵子树,直接对根节点进行操作就行了。

但是显然并不是一棵子树啊。

那就直接新建一个点把新建的点接在下面就好了。

具体来说,对于每一个1操作,新建一个虚点,把所有从这个生长节点长出来的点接在下面。

在处理到第\(l\)棵树时,把这个虚点接到那个生长节点的下面去;处理到第\(r+1\)棵树的时候再把虚点接到前一个生长节点对应的虚点上去。

这样就可以直接查询两个点的路径长度了。

但是有新建的虚点?

直接把实点的权值设为1,虚点的权值设为0,然后查路径和就好了。

但是这是一棵有根树,并不能\(split\)啊。

所以可以查\(s[x]+s[y]-2*s[lca(x,y)]\)?

现在的问题是:怎么在\(LCT\)查\(LCA\)?

先\(access(x)\),然后在\(access(y)\)的时候,最后一个由虚边改为实边的位置就是\(LCA\)。

这个画个图就能理解了吧。

然后这题就做完了。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 4e5+5;
struct node{
int pos,tim,x,y;
bool operator < (const node &b) const
{return pos!=b.pos?pos<b.pos:tim<b.tim;}
}q[N];
int n,m,cnt,Q,fa[N],ch[2][N],val[N],sum[N],grow,real,tot,id[N],L[N],R[N],ans[N];
bool son(int x){return x==ch[1][fa[x]];}
bool isroot(int x)
{
return x!=ch[0][fa[x]]&&x!=ch[1][fa[x]];
}
void pushup(int x)
{
sum[x]=sum[ch[0][x]]+sum[ch[1][x]]+val[x];
}
void rotate(int x)
{
int y=fa[x],z=fa[y],c=son(x);
ch[c][y]=ch[c^1][x];if (ch[c][y]) fa[ch[c][y]]=y;
fa[x]=z;if (!isroot(y)) ch[son(y)][z]=x;
ch[c^1][x]=y;fa[y]=x;pushup(y);
}
void splay(int x)
{
for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
if (!isroot(y)) son(x)^son(y)?rotate(x):rotate(y);
pushup(x);
}
int access(int x)
{
int y=0;
for (;x;y=x,x=fa[x])
splay(x),ch[1][x]=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[0][x]=fa[ch[0][x]]=0;pushup(x);
}
int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
n=gi();m=gi();link(2,1);val[1]=1;id[1]=1;
L[1]=1;R[1]=n;grow=tot=2;real=1;
for (int i=1;i<=m;++i)
{
int opt=gi(),l=gi(),r=gi();
if (!opt)
{
link(id[++real]=++tot,grow);val[tot]=1;
L[real]=l;R[real]=r;
}
if (opt==1)
{
int x=gi();l=max(l,L[x]),r=min(r,R[x]);
if (l>r) continue;
link(++tot,grow);
q[++cnt]=(node){l,i-m,tot,id[x]};q[++cnt]=(node){r+1,i-m,tot,grow};
grow=tot;
}
if (opt==2)
{
int x=gi();
q[++cnt]=(node){l,++Q,id[r],id[x]};
}
}
sort(q+1,q+cnt+1);
for (int i=1;i<=cnt;++i)
if (q[i].tim>0)
{
int res,gg;
access(q[i].x);splay(q[i].x);res=sum[q[i].x];
gg=access(q[i].y);splay(q[i].y);res+=sum[q[i].y];
access(gg);splay(gg);res-=sum[gg]<<1;
ans[q[i].tim]=res;
}
else cut(q[i].x),link(q[i].x,q[i].y);
for (int i=1;i<=Q;++i) printf("%d\n",ans[i]);
return 0;
}

[BZOJ4573][ZJOI2016]大♂森林的更多相关文章

  1. BZOJ4573 : [Zjoi2016]大森林

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

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

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

  3. [ZJOI2016]大森林(LCT)

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

  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. bzoj 4573: [Zjoi2016]大森林

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

  7. P3348 [ZJOI2016]大森林

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

  8. 【LuoguP3348】[ZJOI2016]大森林

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

  9. 【BZOJ4573】[ZJOI2016] 大森林(LCT)

    点此看题面 大致题意: 有\(n\)棵树,初始各有\(1\)个编号为\(1\)的节点,且其为生长节点.\(3\)种操作:将\([l,r]\)区间内的树增加一个新的编号的节点,修改\([l,r]\)区间 ...

随机推荐

  1. 本地yum源建立

    一.openstack(ocata)本地yum源的建立: 1.配置yum缓存: vi /etc/yum.conf 把yum.conf配置改为: [main] cachedir=/var/cache/y ...

  2. Loadrunder脚本篇——Running Time setting之Additional attributes

    作用说明 为Vuser脚本提供额外自定义参数.额外参数设置可应用于所有Vuser脚本类型. 说明: Add:添加一个参数 Remove:移除一个参数 可以在这里先输入一些常用的参数名及对应的值,类似常 ...

  3. iOS 11 Xcode9开发 新特性学习 (警告篇)

    最新版本SDK优化了开发体验,编译过程会提供更多提示警告,建议你修改.这些功能也可以自主选择用或者不用,当然,苹果喜欢你用他推荐的东西... 1 . @avalibale 语法,同步判断当前iOS系统 ...

  4. 服务熔断、降级、限流、异步RPC -- HyStrix

    背景 伴随着业务复杂性的提高,系统的不断拆分,一个面向用户端的API,其内部的RPC调用层层嵌套,调用链条可能会非常长.这会造成以下几个问题: API接口可用性降低 引用Hystrix官方的一个例子, ...

  5. ANSI C和POSIX

    简单的说 ANSI C:标准C API(对应fopen) POSIX:方便在Linux下运行的C API(对应open)

  6. Qt开发动画

    #include <QPropertyAnimation> #include <QDesktopWidget> //下坠 void MainWindow::on_pushBut ...

  7. ResourceBundle和properties 读取配置文件区别

    java.util.ResourceBundle 和java.util.properties 读取配置文件区别 这两个类都是读取properties格式的文件的,而Properties同时还能用来写文 ...

  8. window.open、window.showModalDialog和window.showModelessDialog 的区别[转]

    一.前言 要打开一个可以载入页面的子窗口有三种方法,分别是window.open.window.showModalDialog和window.showModelessDialog. open方法就是打 ...

  9. 【P2158】仪仗队&欧拉函数详解

    来一道数论题吧. 这个题一眼看上去思路明确,应该是数论,但是推导公式的时候却出了问题,根本看不出来有什么规律.看了马佬题解明白了这么个规律貌似叫做欧拉函数,于是就去百度学习了一下这东西. 欧拉函数的含 ...

  10. jsp 内置对象---EL

    ServletRequest : java.lang.String      getParameter(java.lang.String name) 返回一个string           对应 n ...