P3348 [ZJOI2016]大森林(LCT)
对于每个\(1\)操作建一个虚点,以后的\(0\)操作都连在最近建好的虚点上。这样每次整体嫁接的时候,直接把这个虚点断掉它原来的父亲,再\(link\)过去就可以了
求在\(x\)位置的两点之间距离 , 只要之前的换点加点操作完成 , 就可以计算 , 而且也要马上计算 , 之后树的形态就又要变了 , 这样保证了复杂度
关于代码 : 先按思路把离线的事件处理出来
然后发现这种离线的利用虚点的转移只能用\(LCT\)维护
注意 : 只有实点才算\(size\) , 并统计到路径长度中去 , 利用的虚点不算\(size\)
还有\(LCT\)上不\(makeroot\)时求\(LCA\)的求法
注释重构于19.3.29
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define Debug(x) cout<<#x<<"="<<x<<endl
using namespace std;
typedef long long LL;
const int INF=1e9+7;
inline LL read(){
register LL x=0,f=1;register char c=getchar();
while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
while(c>=48&&c<=57)x=(x<<3)+(x<<1)+(c&15),c=getchar();
return f*x;
}
const int MAXN=3e5+5;
const int MAXM=2e5+5;
struct Query{
int pos,id,x,y;
inline friend bool operator<(Query a,Query b){
if(a.pos==b.pos) return a.id<b.id;
return a.pos<b.pos;
}
}q[MAXM];
int Qcnt,Acnt;
int at[MAXN],L[MAXN],R[MAXN],ans[MAXN];
int n,m,p,aux,real;
namespace LCT{
int ch[MAXN][2],fa[MAXN],size[MAXN],val[MAXN];
int st[MAXN],top;
#define ls (ch[rt][0])
#define rs (ch[rt][1])
inline bool chk(int x){return ch[fa[x]][1]==x;}
inline bool isnotroot(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
inline void pushup(int rt){size[rt]=size[ls]+size[rs]+val[rt];}//只要算实点
inline void rotate(int x){
int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1];
ch[y][k]=w,fa[w]=y;
if(isnotroot(y)) ch[z][chk(y)]=x; fa[x]=z;
ch[x][k^1]=y,fa[y]=x;
pushup(y);pushup(x);
}
inline void splay(int x){
while(isnotroot(x)){
int y=fa[x];
if(isnotroot(y)){
if(chk(x)==chk(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
}
inline int access(int x){
int y=0;
for(;x;x=fa[y=x])
splay(x),ch[x][1]=y,pushup(x);
return y;//access(y)时最后跳的虚边的父亲就是lca,即最后的y
}
inline void link(int x,int y){
splay(x);//不能makeroot,只能splay
fa[x]=y;//只有根节点才能连边
}
inline void cut(int x){//和它上面的点断开
access(x);splay(x);
ch[x][0]=fa[ch[x][0]]=0;
pushup(x);
}
#undef ls
#undef rs
}using namespace LCT;
int main(){
n=read(),m=read();
real=1,size[1]=1,val[1]=1,at[1]=1,L[1]=1,R[1]=n;//初始时只有1一个实点
link(p=aux=2,1);
for(int i=1;i<=m;i++){
int op=read(),x=read(),y=read();
if(op==0){
link(at[++real]=++p,aux);///新建一个点连到虚点上去,并记录第real个实点在哪(是所有编号中的第几个)
size[p]=1,val[p]=1;//更新val[]!!! (注意只有这样的实点才有权值)
L[real]=x,R[real]=y;
}
if(op==1){
int t=read();
x=max(x,L[t]),y=min(y,R[t]);//有些树还没这个点
if(x>y) continue;
link(++p,aux);///新建一个点连到虚点上去
//size[p]=0,val[p]=0; 虚点没有val[],不算进路径上有size[]个点
//先按思路把离线的事件处理出来
q[++Qcnt]=(Query){x,i-m,p,at[t]};///到了x就把虚点换成这个 -m是为了使换点操作在加点操作前面.
q[++Qcnt]=(Query){y+1,i-m,p,aux};//到了y+1就换回去
aux=p;//更换虚点了!!! 之后的点要放到新点的下面
}
if(op==2) q[++Qcnt]=(Query){x,++Acnt,at[y],at[read()]};//在x位置的两点之间距离,只要之前的换点加点操作完成,就可以计算,而且也要马上计算,之后树的形态就又要变了
}
sort(q+1,q+Qcnt+1);
for(int i=1;i<=Qcnt;i++){
if(q[i].id>0){
int x=q[i].x,y=q[i].y,&sum=ans[q[i].id];
//由于根节点始终为1,不能makeroot后求路径,所以要用到lca.本题中步数=size[x]+size[y]-2*size[lca].
access(x);splay(x);sum+=size[x];
int lca=access(y);splay(y);sum+=size[y];
access(lca);splay(lca);sum-=size[lca]*2;//打起来真的舒服
}
else{ // 这种离线的利用虚点的转移只能用LCT维护
cut(q[i].x);//和它上面的点断开
link(q[i].x,q[i].y);//然后连到新的点上去
}
}
for(int i=1;i<=Acnt;i++)
printf("%d\n",ans[i]);
}
P3348 [ZJOI2016]大森林(LCT)的更多相关文章
- 洛谷P3348 [ZJOI2016]大森林 [LCT]
传送门 刷了那么久水题之后终于有一题可以来写写博客了. 但是这题太神仙了我还没完全弄懂-- upd:写完博客之后似乎懂了. 思路 首先很容易想到\(O(n^2\log n)\)乘上\(O(\frac{ ...
- [ZJOI2016]大森林(LCT)
题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...
- P3348 [ZJOI2016]大森林
\(\color{#0066ff}{ 题目描述 }\) 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点, ...
- 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)
洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不 ...
- ●洛谷P3348 [ZJOI2016]大森林
题链: https://www.luogu.org/problemnew/show/P3348 题解: LCT,神题 首先有这么一个结论: 每次的1操作(改变生长点操作),一定只会会对连续的一段区间产 ...
- bzoj 4573: [Zjoi2016]大森林 lct splay
http://www.lydsy.com/JudgeOnline/problem.php?id=4573 http://blog.csdn.net/lych_cys/article/details/5 ...
- P3348 [ZJOI2016]大森林(Link-cut-tree)
传送门 题解 题面大意: \(0.\)区间加节点 \(1.\)区间换根 \(2.\)单点询问距离 如果没有\(1\)操作,因为区间加节点都是加在下面,所以我们可以直接把\(n\)棵树压成一棵树,直接询 ...
- BZOJ4573:[ZJOI2016]大森林——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=4573 https://www.luogu.org/problemnew/show/P3348#sub ...
- [ZJOI2016]大森林
Description: 小Y家里有一个大森林,里面有n棵树,编号从1到n 0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例 ...
随机推荐
- Django的Model使用
创建模型 使用Django的模型主要注意两个方面:字段的类型和方法的重写.这里用一个例子来说明,其中包含了常用的字段类型和如何重写方法. from django.db import models cl ...
- Windows系统上release版本程序bug跟踪解决方案-.dmp文件。
使用场景: Win32程序在release模式下编译完成,发送给最终用户使用时,我们的程序有时候也会出现崩溃的情况,这个时候如果能快速定位崩溃原因或提供一些程序崩溃时的状态信息,对我们解决问题将会带来 ...
- lucene、solr中的日期衰减方法-------function query --尚未测试在solr4.8
经常有一种情景是这样的:我们索引了N年的文章,而查询时候无论直接用相关度.或者用时间排序,都是比较鲁莽的:我们想要一种既要相关度比较高,又要时间上比较新的文章. 这时候的解决办法就是,自定义日期衰减的 ...
- day17-jdbc 5.url介绍
url用于标识数据库的位置,用于标识找哪个数据库. 总结:url是路径,其实就是确定是哪个数据库.用来确定我用的是哪一个数据库,并且通知我这个Connection或者是这个DriverManager获 ...
- [poj3686]The Windy's(费用流)
题目大意: 解题关键:指派问题,待更. #include<cstdio> #include<cstring> #include<algorithm> #includ ...
- Express响应方法
下表中响应对象(res)的方法向客户端返回响应,终结请求响应的循环.如果在路由句柄中一个方法也不调用,来自客户端的请求会一直挂起. 方法 描述 res.download() 提示下载文件. res.e ...
- JAVA语法规则总结
单继承多实现 抽象类 抽象方法 使用关键字:abstract修饰的方法就是抽象方法; 抽象方法的形式:只有方法的声明,没有方法体; 抽象方法一般存在于父类中,相当于强制要求子类必须重写该方法,相当于 ...
- 用C#截取指定长度的中英文混合字符串
很早以前写过一篇文章(用C#截取指定长度的中英文混合字符串),但是对性能没有测试,有人说我写的这个方法性能有问题,后来想,可能真会有BT之需求要求传入一个几万K甚至几M体积的字符串进来,那将会影响正则 ...
- Java50道经典习题-程序45 被9整除
题目:判断一个素数能被几个9整除分析:素数只能被1和其本身整除,不能被9整除,所以返回false import java.util.Scanner; public class Prog45{ publ ...
- springcloud +spring security多种验证方式之第三方token生成自己的token通过校验和自己的表单验证大体流程
步骤: 1.继承 WebSecurityConfigurerAdapter.class,其中使用两个过滤器,一个spring scurity自带的UsernamePasswordAuthenticat ...