洛谷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\)棵树压成一棵树,直接询 ...
随机推荐
- redis系列--你真的入门了吗?redis4.0入门~
前言 redis作为nosql家族中非常热门的一员,也是被大型互联网公司所青睐,无论你是开发.测试或者运维,学习掌握它总会为你的职业生涯增色添彩. 当然,你或多或少已经了解redis,但是你是否了解其 ...
- 2017-2018-2 20155315《网络对抗技术》Exp6 :信息搜集与漏洞扫描
实验目的 进行信息搜集的工作,为实战做准备 教程 实验内容 外围信息搜集 NMAP OpenVAS 实验步骤 (一)各种搜索技巧的应用 实战的前提是进行信息搜索.当我们想要有针对地进行操作的时候,就要 ...
- 复选框、单选框 jquery判断是否选中Demo
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="eachcheckbox.a ...
- Luogu P2055 [ZJOI2009]假期的宿舍
一道网络有关的问题,还是一句话 网络流重在建模! 这里主要讲两种算法. 1.二分图匹配: 分析题意,我们可以知道题目要求是让所有留在学校的人都能有床睡 而 所有留在学校的人=本校不回家的人+外校的人: ...
- 01-BAT算法特训班
- CF1096G Lucky Tickets
https://www.luogu.org/problemnew/show/CF1096G 显然dp出用\(\frac{n}{2}\)个数能拼出来的每个数的方案数,平方相加就行了,dp显然ntt+快速 ...
- 行级安全(Row-Level Security)
通过授予和拒绝(Grant/Deny)命令控制用户的权限,只能控制用户对数据库对象的访问权限,这意味着,用户访问的粒度是对象整体,可以是一个数据表,或视图等,用户要么能够访问数据库对象,要么没有权限访 ...
- photoshop cs6安装过程中安装程序遇到错误:请重启计算机,解决办法
1.关闭防火墙和杀毒软件 2.删除注册表 依次展开HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager目录,找到其中的 ...
- c++ Arx二次开发创建椭圆和样条曲线
一.本节课程 c++ Arx二次开发创建椭圆和样条曲线 二.本节要讲解的知识点 1.如何应用C++ ARX二次开发创建椭圆(对AcDbEllipse类的构造函数的直接封装和根据外接矩形来创建椭圆) 2 ...
- 腾讯/阿里/百度 BAT人才体系的职位层级、薪酬、晋升标准
互联网圈有这么一句话:百度的技术,阿里的运营,腾讯的产品.那么代表互联网三座大山的BAT,内部人才体系有什么区别呢?今天老李就带领大家看一看~ ★ 腾讯 ★ 1. 职级 腾讯职级体系分6级,最低1 ...