洛谷题目传送门

思路分析

最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了)

考虑如何优化算法。如果没有1操作,肯定每个树都长一样。有了1操作,就来仔细分析一下对不同树的影响。

假设有一个1操作形如\(l\ r\ x\),那么从微观来看差异,我们只关注第l-1棵树和第l棵树。再假设以后都没有了0操作,那么我们可以认为,第l棵树是第l-1棵树把这个1操作以后嫁接在原来生长节点上的所有节点(以及所有子树)全部转而嫁接到x上。再看第r棵树和第r+1棵树,是不是可以认为又把这些子树嫁接回来了对吧?

注意到题目没有说在线,又因为1操作是有限的,只有两个端点,那么如果我们能够快速从一棵树转移到下一颗树,复杂度就能够保证了。

问题就在于,怎样把一堆子树的父亲全部转移。zcy太强辣,我什么ETT都不会。。。。。。

所以可能又要用一个虚点的套路。对于每个1操作建一个虚点,以后的0操作都连在最近建好的虚点上。这样每次整体嫁接的时候,直接把这个虚点断掉它原来的父亲,再link过去就大功告成啦!一开始默认所有虚点都在一起(表示默认生长节点从来没变过),把1操作拆成两个嫁接操作,再对所有操作以端点为第一关键字,原时间顺序为第二关键字排序,再从左到右一个个处理。

至于2操作,可以发现等一棵树全处理完再回答关于这棵树的所有询问是完全没有问题的。具体实现又怎么办?首先要设点权了,实点(0操作加的点)为1,虚点为0。然后就split?NoNoNo!第一,这个树是有根的(根为1),强行makeroot会破坏原先的父子关系;第二,两个点在LCT中的LCA可能是虚点!那又如何是好?又来一波树上差分,答案是\(s[x]+s[y]-2*s[\)LCT中的LCA\(]\)(貌似不太方便直接证明,自己举一些栗子yy就好啦qwq)

然后在LCT中如何求LCA呢?就是access(x)再接着access(y),access(y)过程中最后一个跳到的虚边的父节点(在access完成后函数里的x会变成0,而y就是这个点)。熟悉LCT的各种性质应该是可以很轻松的知道这种方法。(关于性质方面蒟蒻的LCT总结依旧希望路过的Dalao们指正qwq)

蛇皮压行卡常(懒得写fread了)巨丑无比的代码

不过变量名应该是很好懂的

#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define R RG int
#define I inline
#define G ch=getchar()
#define lc c[x][0]
#define rc c[x][1]
#define qr(P,O,X,Y) qry[++q]=(QRY){P,O,X,Y}
using namespace std;
const int N=300009;
struct QRY{//封结构体,把嫁接和询问按顺序排序
int pos,ord,x,y;
I bool operator<(RG QRY a)const{
return pos<a.pos||(pos==a.pos&&ord<a.ord);
}
}qry[N];
int f[N],c[N][2],s[N],gl[N],gr[N],at[N],ans[N];
bool v[N];
I void in(R&x){
register char G;
while(ch<'-')G;
x=ch&15;G;
while(ch>'-')x*=10,x+=ch&15,G;
}
I bool nrt(R x){return c[f[x]][0]==x||c[f[x]][1]==x;}
I void up(R x){s[x]=s[lc]+s[rc]+v[x];}
I void rot(R x){
R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
if(nrt(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
up(f[w]=y);f[y]=x;f[x]=z;
}
I void sp(R x){
for(R y;nrt(x);rot(x))
if(nrt(y=f[x]))rot((c[f[y]][0]==y)^(c[y][0]==x)?x:y);
up(x);
}
I int ac(R x){R y=0;while(x)sp(x),rc=y,up(y=x),x=f[x];return y;}
I void ct(R x){ac(x);sp(x);lc=f[lc]=0;up(x);}
I void lk(R x,R y){sp(x);f[x]=y;}//蒟蒻的LCT越写越丑了。。。
int main(){
R q=0,tot=0,n,m,p,real,aux,i,op,l,r,x,y;
in(n);in(m);
real=v[1]=s[1]=at[1]=gl[1]=1;gr[1]=n;
lk(p=aux=2,1);//一开始也要来一个虚点
for(i=1;i<=m;++i){
in(op);in(l);in(r);
if(op==0){//默认一开始全长在一起
lk(at[++real]=++p,aux);v[p]=s[p]=1;
gl[real]=l;gr[real]=r;
}//gl和gr方便下面把无用的区间去掉
else if(op==1){//有些区间连这个点都没长出来,直接取min,max
in(x);l=max(l,gl[x]);r=min(r,gr[x]);
if(l>r)continue;
lk(++p,aux);
qr(l,i-m,p,at[x]);qr(r+1,i-m,p,aux);//-m是为了把所有嫁接放到询问之前
aux=p;//更新生长节点位置
}
else in(x),qr(l,++tot,at[r],at[x]);
}
sort(qry+1,qry+q+1);
for(i=1;i<=q;++i){
if(qry[i].ord>0){
ac(x=qry[i].x);sp(x);r=s[x];
l=ac(y=qry[i].y);sp(y);r+=s[y];
ac(l);ans[qry[i].ord]=r-(s[l]<<1);//差分一下
}
else ct(qry[i].x),lk(qry[i].x,qry[i].y);
}
for(i=1;i<=tot;++i)printf("%d\n",ans[i]);
return 0;
}

洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)的更多相关文章

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

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

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

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

  3. 洛谷3348 大森林 (LCT + 虚点 + 树上差分)

    这可真是道神仙题QWQ问了好多\(dalao\)才稍微明白了一丢丢做法 首先,我们假设不存在\(1\)操作,那么对于询问的一段区间中的所有的树,他们的形态应该是一样的 甚至可以直接理解为\(0\)操作 ...

  4. [ZJOI2016]大森林(LCT)

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

  5. P3348 [ZJOI2016]大森林

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

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

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

  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. 洛谷P2387 [NOI2014]魔法森林(LCT)

    魔法森林 题目传送门 解题思路 把每条路按照\(a\)的值从小到大排序.然后用LCT按照b的值维护最小生成树,将边按照顺序放入.如果\(1\)到\(n\)有了一条路径,就更新最小答案.这个过程就相当于 ...

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

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

随机推荐

  1. 1.5《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——清屏

    使用命令行时,使用clear命令清除屏幕非常方便: $ clear 键盘简写为^L.(Ctrl + L) 同样地,使用完终端当前窗口或标签页,使用exit命令退出进程: $ exit 键盘简写为^D ...

  2. 【WPF】给TextBox添上Label

    原文:[WPF]给TextBox添上Label 引言     在客户端开发中,要说出现频率大的控件,必定有TextBox的身影.然而在TextBox的旁边通常得有个基友Label,形影不离.为此,我们 ...

  3. 【php增删改查实例】第五节 - easyUI的基本使用

    1. 列表组件 datagrid 1.1 创建一个grid.html <html> <head> <meta charset="utf-8" /> ...

  4. libgdx学习记录4——舞台Stage

    libgdx总的来说是一个框架,而不是一个成熟的游戏引擎.Stage是其中一个比较好的封装,里面自带Camera.SpriteBatch等常用渲染绘图工具. 下面是一个简单的添加图片,并让镜头左右上下 ...

  5. 内存和CPU资源控制

    数据库系统的资源是指内存和CPU(处理器)资源,拥有资源的多寡,决定了数据查询的性能.当一个SQL Server实例上,拥有多个独立的工作负载(workload)时,使用资源管理器(Resource ...

  6. 【Orleans开胃菜系列2】连接Connect源码简易分析

    [Orleans开胃菜系列2]连接Connect源码简易分析 /** * prism.js Github theme based on GitHub's theme. * @author Sam Cl ...

  7. Zabbix使用总结

    1. CentOS 7上启动zabbix-server失败,/var/log/messages中的报错信息如下: Feb :: mysql-server1 systemd: Starting Zabb ...

  8. STM8S——8位基本定时器(TIM4)

    简介:该定时器由一个带可编程预分频器的8位自动重载的向上计数器所组成,它可以用来作为时基发生器,具有溢出中断功能. 主要功能: (1)8位向上计数的自动重载计数器: (2)3位可编程的预分配器(可在运 ...

  9. eclipse中怎么找项目部署的路径和找编译后的class路径

    1.快捷键 ctrl+shift+R,会默认显示你的源文件.java的路径,如果没有.class的话,点击右上角的三角,选中  Show Derived Resource; 2.打开出现下图 3.按下 ...

  10. dokuwiki 配置 sendmail 邮件发送

    dokuwiki 发送邮件有2种方式: 一是直接使用 PHP 自带发送功能,需要配置 PHP.ini 文件, 我没试过,可参考官网 https://www.dokuwiki.org/tips:mail ...