bzoj 4573 大森林

  • 由于树上路径是唯一的,查询合法的两个点间路径长度显然与其他加点操作无关,所以可以离线处理,将所有的查询放在加点后.
  • 这样我们可以对每棵树都在上颗树的基础上处理好形态后,处理这颗树上的询问.
  • 考虑若没有操作 \(1\) ,则所有树都一模一样.那么两棵树的形态不同,一定是某一颗执行了操作 \(1\) ,另一个却没有.只需要在每个关键位置(修改开始或结束时)将原来生长点所有子树挂到新的生长点下.
  • 若暴力移动子树,当子树数目较大时就会很劣.可以对每个操作 \(1\) 建立一个虚点,将这个操作内挂上去的点都挂在虚点上,于是只需要移动虚点就可以了.注意将虚点 \(siz\) 设置为 \(0\) .
  • 查询答案时,使用 \(dep[x]+dep[y]-2*dep[lca]\) 计算,避免虚点造成的影响.
  • 直接用 \(split(x,y)\) 会出问题.因为你把路径抠出来之后不知道要不要减去 \(1\) .
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
int x=0;
bool pos=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
pos=0;
for(;isdigit(ch);ch=getchar())
x=x*10+ch-'0';
return pos?x:-x;
}
const int MAXN=3e5+10;
struct query{
int pos,op,x,y;
bool operator < (const query &rhs) const
{
return pos==rhs.pos?op<rhs.op:pos<rhs.pos;
}
}q[MAXN];
namespace LCT{
int stk[MAXN],tp;
int tot;
struct node{
int ch[2],fa;
int rev;
int siz,val;
node()
{
fa=ch[0]=ch[1]=0;
rev=0;
siz=val=0;
}
}tree[MAXN];
#define root tree[x]
#define lson tree[root.ch[0]]
#define rson tree[root.ch[1]]
inline void pushup(int x)
{
root.siz=lson.siz+root.val+rson.siz;
}
void inverse(int x)
{
swap(root.ch[0],root.ch[1]);
root.rev^=1;
}
void pushdown(int x)
{
if(root.rev)
{
if(root.ch[0])
inverse(root.ch[0]);
if(root.ch[1])
inverse(root.ch[1]);
root.rev=0;
}
}
bool isroot(int x)
{
int y=root.fa;
return tree[y].ch[0]!=x && tree[y].ch[1]!=x;
}
void rotate(int x)
{
int y=tree[x].fa,z=tree[y].fa;
int k=tree[y].ch[1]==x;
if(!isroot(y))
tree[z].ch[tree[z].ch[1]==y]=x;
tree[x].fa=z;
tree[tree[x].ch[k^1]].fa=y;
tree[y].ch[k]=tree[x].ch[k^1];
tree[x].ch[k^1]=y;
tree[y].fa=x;
pushup(y);
pushup(x);
}
void splay(int x)
{
tp=0;
stk[++tp]=x;
for(int pos=x;!isroot(pos);pos=tree[pos].fa)
stk[++tp]=tree[pos].fa;
while(tp)
pushdown(stk[tp--]);
while(!isroot(x))
{
int y=tree[x].fa,z=tree[y].fa;
if(!isroot(y))
(tree[y].ch[0]==x)^(tree[z].ch[0]==y)?rotate(x):rotate(y);
rotate(x);
}
pushup(x);
}
int Access(int x)
{
int y;
for(y=0;x;y=x,x=tree[x].fa)
{
splay(x);
tree[x].ch[1]=y;
pushup(x);
}
return y;
}
void makeroot(int x)
{
Access(x);
splay(x);
inverse(x);
}
int findroot(int x)
{
Access(x);
splay(x);
while(tree[x].ch[0])
x=tree[x].ch[0];
return x;
}
void split(int x,int y)
{
makeroot(x);
Access(y);
splay(y);
}
void Link(int x,int y)
{
makeroot(x);
tree[x].fa=y;
}
void Cut(int x)
{
Access(x);
splay(x);
tree[tree[x].ch[0]].fa=0;
tree[x].ch[0]=0;
pushup(x);
}
}
using namespace LCT;
int solve(int x,int y)
{
int ans=0;
Access(x);
splay(x);
ans+=tree[x].siz;
int lca=Access(y);
splay(y);
ans+=tree[y].siz;
Access(lca);
splay(lca);
ans-=2*tree[lca].siz;
return ans;
}
void newnode(int v)
{
int x=++tot;
root.val=root.siz=v;
}
int n,m;
int last,id[MAXN],idd,cnt,L[MAXN],R[MAXN],qs;
inline void insq(int pos,int op,int x,int y)
{
++cnt;
q[cnt].pos=pos,q[cnt].op=op;
q[cnt].x=x,q[cnt].y=y;
}
int ans[MAXN];
int main()
{
tot=0;
n=read(),m=read();
newnode(1),idd=1,L[1]=1,R[1]=n,id[1]=1;
newnode(0),last=2,Link(2,1);
for(int i=1;i<=m;++i)
{
int type=read();
if(type==0)
{
int l=read(),r=read();
newnode(1);
L[++idd]=l,R[idd]=r,id[idd]=tot;
insq(1,i-m,tot,last);
}
else if(type==1)
{
int l=read(),r=read(),x=read();
l=max(l,L[x]),r=min(r,R[x]);
if(l<=r)
{
newnode(0);
Link(tot,last);
insq(l,i-m,tot,id[x]);
insq(r+1,i-m,tot,last);
last=tot;
}
}
else
{
int x=read(),u=read(),v=read();
insq(x,++qs,id[u],id[v]);
}
}
sort(q+1,q+cnt+1);
for(int i=1,j=1;i<=n;++i)
{
for(;j<=cnt && q[i].pos==i;++j)
{
if(q[j].op<=0)
{
Cut(q[j].x);
Link(q[j].x,q[j].y);
}
else
ans[q[j].op]=solve(q[j].x,q[j].y);
}
}
for(int i=1;i<=qs;++i)
printf("%d\n",ans[i]);
return 0;
}

bzoj 4573 大森林的更多相关文章

  1. [BZOJ 4573][ZJOI 2016]大森林

    [LOJ 2092][BZOJ 4573][UOJ 195][ZJOI 2016]大森林 题意 给定一个树序列, 初始时所有树都只有一个点, 要求支持三种操作: 区间种树(在某个特定点上长出一个子结点 ...

  2. 【刷题】BZOJ 4573 [Zjoi2016]大森林

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

  3. bzoj 4573: [Zjoi2016]大森林

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

  4. BZOJ4573:[ZJOI2016]大森林——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=4573 https://www.luogu.org/problemnew/show/P3348#sub ...

  5. BZOJ 3684 大朋友和多叉树

    BZOJ 3684 大朋友和多叉树 Description 我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树.对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的: ...

  6. 「ZJOI2016」大森林 解题报告

    「ZJOI2016」大森林 神仙题... 很显然线段树搞不了 考虑离线操作 我们只搞一颗树,从位置1一直往后移动,然后维护它的形态试试 显然操作0,1都可以拆成差分的形式,就是加入和删除 因为保证了操 ...

  7. [ZJOI2016]大森林(LCT)

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

  8. [ZJOI2016]大森林

    Description: 小Y家里有一个大森林,里面有n棵树,编号从1到n 0 l r 表示将第 l 棵树到第 r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个 0 号操作叶子标号加 1(例 ...

  9. [BZOJ 3652]大新闻

    [BZOJ 3652] 大新闻 题意 随机从 \([0,n)\) 中选取一个整数 \(x\), 并从 \([0,n)\) 中再选取一个整数 \(y\). 有 \(p\) 的概率选取一个能令 \(x\o ...

随机推荐

  1. LA 6893 The Big Painting(矩阵Hash)

    https://vjudge.net/problem/UVALive-6893 题意: 给出一个小矩阵和大矩阵,在大矩阵中能找到相同的小矩阵. 思路: 矩阵Hash,先对小矩阵计算出它的Hash值,然 ...

  2. 面试笔试总结(二)之 C++基础

    上节,一定要写出基于引用计数的智能指针 明白单例模式 会写出代码 复习: 1- 2- 推荐leveldb ....是c++的写代码很规范的地方?比如智能指针在这里... 对类进行改造 可以改成Sing ...

  3. Linux加载/usr/local/lib中的so库

    > https://my.oschina.net/u/2306127/blog/1617233 > https://blog.csdn.net/csfreebird/article/det ...

  4. Cookie和Session的工作原理及比较

    一.Cookie详解 (1)简介 因为HTTP协议是无状态的,即服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现.在典型的网上购物场景中,用户浏览了几个页面,买了一盒饼干和两饮料 ...

  5. 使用IDEA创建SpringBoot自定义注解

    创建SpringBoot项目 添加组织名 选择web 输入项目名称 创建后目录结构为 使用Spring的AOP先加入Maven依赖 <dependency> <groupId> ...

  6. express中的错误处理

    错误处理 定义错误处理中间件和定义其他中间件一样,除了需要 4 个参数,而不是 3 个,其格式如下 (err, req, res, next).例如: app.use(function(err, re ...

  7. 图片服务器(FastDFS)的搭建

    1.1 什么是FastDFS FastDFS是用c语言编写的一款开源的分布式文件系统.FastDFS为互联网量身定制,充分考虑了冗余备份.负载均衡.线性扩容等机制,并注重高可用.高性能等指标,使用Fa ...

  8. Python3安装(二)

    因为Python是跨平台的,它可以运行在Windows.Mac和各种Linux/Unix系统上.在Windows上写Python程序,放到Linux上也是能够运行的. 要开始学习Python编程,首先 ...

  9. C#运行批处理【转】

    /// <summary> /// C#运行bat文件 /// </summary> /// <param name="batPath">< ...

  10. MoreEffectiveC++Item35(操作符)(条款5-8)

    条款5 对定制的"类型转换函数"保持警惕 条款6 区别increment/decrement操作符的前值和后置形式 条款7 千万不要重载&&,||,和,操作符 条款 ...