bzoj 4573: [Zjoi2016]大森林 lct splay
http://www.lydsy.com/JudgeOnline/problem.php?id=4573
http://blog.csdn.net/lych_cys/article/details/53515748#
lct的难点大概是转换的部分。
这道题需建两种权值不同的点,每次更换生长节点建立权值为0的虚点,生长新点建立权值为1的实点,因为最开始有一个带权值的生长节点,那么建一个虚点一个实点来表示。
因为求的东西追根溯源只是链,每棵树从根到某点的链的结构都是交错的所以可以这样压缩点以及点点之间的关系。
实点需要连向最近建立的虚点,虚点需要连向最近建立的实点,注意一下离线前虚点被连成一条链,离线操作时某一个控制范围结束也是将这个虚点连回原来的链上。
按照操作的树的起始位置和操作时间排序,就可以离线处理了。这个离线操作大概可以视为几个实点虚点交错的链两端断开连接。
计算距离lca实现,两次access+splay计算的两个点x和y到根的距离和,他们的lca其实是 access y 的时候的最后一个连通块的入点,这个应该想一下可以想到。
access lca的时候我才发现access是删掉整个右子树的,这样操作顺利删掉了y到lca的这段距离。(原来以前都没有意识到access的原理么我果然是个傻子)。
注释什么的代码里解释的很详细了。
过了157个人,时间空间排名83竟然有点开心(还有74个人想的板子没有我抄的板子快呀(有毒))。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=;
int n,m;
int ch[maxn][]={},fa[maxn]={},siz[maxn]={};//splay相关
int sum[maxn]={},num[maxn]={};//splay子树和,点值(0/1)
int l[maxn]={},r[maxn]={};//对实点的记录,每个实点存在的树的标号范围
int b[maxn]={};//编号为i的实点的编号为b[i]
int tly=,cnt=;//tly是对点数的记录,cnt表示当前生成到编号为cnt的实点
int ans[maxn]={};
struct nod{
int z,ti,x,y;//操作的树的序号 操作时间(排序的一个依据) 需要连的两个点
}a[maxn*];int tot=;
bool mcmp(nod aa,nod bb){ return aa.z<bb.z||(aa.z==bb.z&&aa.ti<bb.ti); }
//离线操作是先按位置后按地点的方式排列的。
inline bool isroot(int x){ return ch[fa[x]][]!=x&&ch[fa[x]][]!=x;}
inline void updata(int x){ sum[x]=sum[ch[x][]]+sum[ch[x][]]+num[x];}
inline void newp(int v){ tly++;num[tly]=sum[tly]=v; }
inline void init(int z,int ti,int x,int y){
a[++tot].z=z;a[tot].ti=ti;a[tot].x=x;a[tot].y=y;
}
void rotate(int x){
int y=fa[x];int fy=fa[y];
int l=ch[y][]==x?:;int r=l^;
if(!isroot(y)){
if(ch[fy][]==y) ch[fy][]=x;
else ch[fy][]=x;
}
fa[ch[x][r]]=y; fa[x]=fy; fa[y]=x;
ch[y][l]=ch[x][r]; ch[x][r]=y;
updata(y);
}
void splay(int x){
while(!isroot(x)){
int y=fa[x];int fy=fa[y];
if(!isroot(y)){
if((ch[y][]==x)^(ch[fy][]==y)) rotate(x);
else rotate(y);
}
rotate(x);
}updata(x);
}
int access(int x){
int y=;
while(x){
splay(x);
ch[x][]=y;
updata(x);
y=x;x=fa[x];//这里的y和上面的含义不同,这里的是儿子。
}return y;
}
void cut(int x){
access(x);splay(x);
fa[ch[x][]]=;ch[x][]=;updata(x);
}
void link(int x,int y){ cut(x);fa[x]=y;}
int main(){
scanf("%d%d",&n,&m);
newp();cnt=;b[]=l[]=;r[]=n;
newp();fa[]=;
int x,y,z,f;int now=;
for(int i=;i<=m;i++){
scanf("%d",&f);
if(!f){
cnt++;
scanf("%d%d",&l[cnt],&r[cnt]);
newp();b[cnt]=tly;
init(,i-m,tly,now);//操作的树的序号 时间(排序的两个依据) 需要连的两个点
}
else if(f==){
scanf("%d%d%d",&x,&y,&z);
x=max(x,l[z]);y=min(y,r[z]);
if(x<=y){
newp();
if(x>)fa[tly]=now;
init(x,i-m,tly,b[z]);
init(y+,i-m,tly,now);
now=tly;
}
}
else{
scanf("%d%d%d",&z,&x,&y);
init(z,i,b[x],b[y]);
}
}
sort(a+,a++tot,mcmp);
memset(ans,-,sizeof(ans));
int j=;
for(int i=;i<=n;i++){
for(;j<=tot&&a[j].z==i;j++){
if(a[j].ti>){
access(a[j].x);splay(a[j].x);
ans[a[j].ti]=sum[a[j].x];
x=access(a[j].y);
splay(a[j].y);
ans[a[j].ti]+=sum[a[j].y];
access(x);splay(x);
ans[a[j].ti]-=sum[x]*; }
else{
link(a[j].x,a[j].y);
}
}
}for(int i=;i<=m;i++)if(ans[i]!=-)printf("%d\n",ans[i]);
return ;
}
bzoj 4573: [Zjoi2016]大森林 lct splay的更多相关文章
- 【刷题】BZOJ 4573 [Zjoi2016]大森林
Description 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力.小 ...
- bzoj 4573: [Zjoi2016]大森林
Description 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树 都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. ...
- [ZJOI2016]大森林(LCT)
题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y掌握了一种 ...
- 洛谷P3348 [ZJOI2016]大森林 [LCT]
传送门 刷了那么久水题之后终于有一题可以来写写博客了. 但是这题太神仙了我还没完全弄懂-- upd:写完博客之后似乎懂了. 思路 首先很容易想到\(O(n^2\log n)\)乘上\(O(\frac{ ...
- 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(例 ...
- P3348 [ZJOI2016]大森林
\(\color{#0066ff}{ 题目描述 }\) 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点, ...
- 【LuoguP3348】[ZJOI2016]大森林
题目链接 题目描述 小Y家里有一个大森林,里面有n棵树,编号从1到n.一开始这些树都只是树苗,只有一个节点,标号为1.这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力. 小Y ...
- UOJ#195. 【ZJOI2016】大♂森林 LCT
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ195.html 题解 首先询问都可以放到最后处理. 对于操作,我们把它差分一下离线下来. 现在的问题就是从 ...
随机推荐
- 【译】第十三篇 Integration Services:SSIS变量
本篇文章是Integration Services系列的第十三篇,详细内容请参考原文. 简介在前一篇我们结合了之前所学的冒泡.日志记录.父子模式创建一个自定义的SSIS包日志记录模式.在这一篇,我们将 ...
- 『实践』百度地图给多个marker添加右键菜单(删除、更新)
js: $.getJSON("./GetStationPlaceServlet",function(json){ for(var i=0;i<json.length;i++) ...
- Python操作Excle
python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库.可从这里下载https://pypi.python.org/pypi.下面分别记录p ...
- 2.Centos-Docker-shipyard中文版安装
1.准备(所有服务器都要执行) a.设置主机名和hosts vi /etc/hosts 192.168.1.2 centos-master 192.168.1.4 centos-minion-2 b. ...
- TF-搞不懂的TF矩阵加法
看谷歌的demo mnist,卷积后加偏执量的代码 h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)h_pool1 = max_pool ...
- js中this揭秘
前端面试题中经常会考this指向问题,初学者通常都会晕头转向,不知所以然.今天我就来讲讲js中this指向问题. this指向大概分为5种情况,记住这6个规律,基本上面试题都能解决. 通过圆括号直接调 ...
- 密码记录工具keepass保存密码
https://www.cnblogs.com/wicub/p/5753005.html
- GreenPlum学习笔记:split_part与string_to_array字符截取
偶遇一个需求:想按某个指定符号分割之后,提取字符. 例如:tag = '休闲,娱乐,运动,玩耍',想提取"休闲"这个词. 方法一:string_to_array select st ...
- Knockout.Js官网学习(模版绑定)
模板绑定器 如今页面结构越来越复杂,仅仅依靠foreach已经不足以我们的使用,这个时候我们就需要模板的存在,模板的优点自然很多,首先会让页面整洁,同时修改起来也可以方面的定位,最重要的是ko可以条件 ...
- servlet 学习笔记(三)
同一用户的不同页面共享数据有以下四种方法: 1.sendRedirect()跳转 2.session技术 3.隐藏表单提交(form) 4. cookie技术(小甜饼) --------------- ...