洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)
思路分析
最简单粗暴的想法,肯定是大力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,虚点,树上差分)的更多相关文章
- 洛谷P3348 [ZJOI2016]大森林 [LCT]
传送门 刷了那么久水题之后终于有一题可以来写写博客了. 但是这题太神仙了我还没完全弄懂-- upd:写完博客之后似乎懂了. 思路 首先很容易想到\(O(n^2\log n)\)乘上\(O(\frac{ ...
- ●洛谷P3348 [ZJOI2016]大森林
题链: https://www.luogu.org/problemnew/show/P3348 题解: LCT,神题 首先有这么一个结论: 每次的1操作(改变生长点操作),一定只会会对连续的一段区间产 ...
- 洛谷3348 大森林 (LCT + 虚点 + 树上差分)
这可真是道神仙题QWQ问了好多\(dalao\)才稍微明白了一丢丢做法 首先,我们假设不存在\(1\)操作,那么对于询问的一段区间中的所有的树,他们的形态应该是一样的 甚至可以直接理解为\(0\)操作 ...
- [ZJOI2016]大森林(LCT)
题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...
- P3348 [ZJOI2016]大森林
\(\color{#0066ff}{ 题目描述 }\) 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点, ...
- P3348 [ZJOI2016]大森林(LCT)
Luogu3348 BZOJ4573 LOJ2092 题解 对于每个\(1\)操作建一个虚点,以后的\(0\)操作都连在最近建好的虚点上.这样每次整体嫁接的时候,直接把这个虚点断掉它原来的父亲,再\( ...
- bzoj 4573: [Zjoi2016]大森林 lct splay
http://www.lydsy.com/JudgeOnline/problem.php?id=4573 http://blog.csdn.net/lych_cys/article/details/5 ...
- 洛谷P2387 [NOI2014]魔法森林(LCT)
魔法森林 题目传送门 解题思路 把每条路按照\(a\)的值从小到大排序.然后用LCT按照b的值维护最小生成树,将边按照顺序放入.如果\(1\)到\(n\)有了一条路径,就更新最小答案.这个过程就相当于 ...
- P3348 [ZJOI2016]大森林(Link-cut-tree)
传送门 题解 题面大意: \(0.\)区间加节点 \(1.\)区间换根 \(2.\)单点询问距离 如果没有\(1\)操作,因为区间加节点都是加在下面,所以我们可以直接把\(n\)棵树压成一棵树,直接询 ...
随机推荐
- 【转】php容易犯错的10个地方
原文地址: http://www.toptal.com/php/10-most-common-mistakes-php-programmers-make 译文地址:http://codecloud.n ...
- C++面向对象模型
1. 基础知识 C++编译器怎样完毕面向对象理论到计算机程序的转化? 换句话:C++编译器是怎样管理类.对象.类和对象之间的关系 详细的说:详细对象调用类写的方法,那,c++编译器是怎样区分,是那个详 ...
- Liunx-mkdir命令
1. 新建一个文件夹 one 2. 新建三个文件夹three,four,five 3. 新建一个多层级文件夹 201904/a/01
- 大数据入门第十四天——Hbase详解(二)基本概念与命令、javaAPI
一.hbase数据模型 完整的官方文档的翻译,参考:https://www.cnblogs.com/simple-focus/p/6198329.html 1.rowkey 与nosql数据库们一样, ...
- WPF XML序列化保存数据 支持Datagrid 显示/编辑/添加/删除数据
XML序列化保存数据 using System; using System.Collections.Generic; using System.Linq; using System.Text; usi ...
- 20155202《网络对抗》Exp8 Web基础
20155202<网络对抗>Exp8 Web基础 基础问题回答 什么是表单? 表单是一个包含表单元素的区域,表单元素是允许用户在表单中(比如:文本域.下拉列表.单选框.复选框等等)输入信息 ...
- Servlet——提交表单信息,Servlet之间的跳转
HTML表单标签:<form></form> 属性: actoion: 提交到的地址,默认为当前页面 method: 表单提交方式 有get和post两种方式,默认为get ...
- 轻量级直播服务器SRS安装及编译
最近由于公司开发的需要--互动会议,开始研究直播中的技术.由于自身没有接触过虚拟机导致在研究的过程中遇到了很大的问题,首先官方GitHub给出的文档并没有清晰的指出编译是需要通过何种方式进行编译?以下 ...
- PowerShell 操作 Azure SQL Active Geo-Replication
前文中我们比较全面的介绍了 Azure SQL Database Active Geo-Replication 的主要特点和优势.接下来我们将从自动化的角度介绍如何通过 PowerShell 在项目中 ...
- 【翻译】给初学者的 Neural Networks / 神经网络 介绍
本文翻译自 SATYA MALLICK 的 "Neural Networks : A 30,000 Feet View for Beginners" 原文链接: https:// ...