题目描述
小 Y 家里有一个大森林,里面有
n
n
n 棵树,编号从
1
1
1 到
n
n
n。一开始这些树都只是树苗,只有一个节点,标号为
1
1
1。这些树都有一个特殊的节点,我们称之为生长节点,这些节点有生长出子节点的能力。小 Y 掌握了一种魔法,能让第
l
l
l 棵树到第
r
r
r 棵树的生长节点长出一个子节点。同时她还能修改第
l
l
l 棵树到第
r
r
r 棵树的生长节点。她告诉了你她使用魔法的记录,你能不能管理她家的森林,并且回答她的询问呢?
第一行包含两个正整数
n
,
m
n,m
n,m,表示共有
n
n
n 棵树和
m
m
m 个操作。
接下来 m m m 行,每行包含若干非负整数表示一个操作,操作格式为:
0 l r
表示将第
l
l
l 棵树到第
r
r
r 棵树的生长节点下面长出一个子节点,子节点的标号为上一个
0
0
0 号操作叶子标号加
1
1
1(例如,第一个
0
0
0 号操作产生的子节点标号为
2
2
2),
l
l
l 到
r
r
r 之间的树长出的节点标号都相同。保证
1
≤
l
≤
r
≤
n
1 \leq l \leq r \leq n
1≤l≤r≤n 。
1 l r x
表示将第
l
l
l 棵树到第
r
r
r 棵树的生长节点改到标号为
x
x
x 的节点。对于
i
i
i
(
l
≤
i
≤
r
)
(l \leq i \leq r)
(l≤i≤r) 这棵树,如果标号
x
x
x 的点不在其中,那么这个操作对该树不产生影响。保证
1
≤
l
≤
r
≤
n
1 \leq l \leq r \leq n
1≤l≤r≤n ,
x
x
x 不超过当前所有树中节点最大的标号。
2 x u v
询问第
x
x
x 棵树中节点
u
u
u 到节点
v
v
v 点的距离,也就是在第
x
x
x 棵树中从节点
u
u
u 和节点
v
v
v 的最短路上边的数量。保证
1
≤
x
≤
n
1 \leq x \leq n
1≤x≤n,这棵树中节点
u
u
u 和节点
v
v
v 存在。
输出包括若干行,按顺序对于每个小 Y 的询问输出答案
样例输入
5 5
0 1 5
1 2 4 2
0 1 4
2 1 1 3
2 2 1 3
样例输出
1
2
数据范围
N ≤ 1 0 5 , M ≤ 2 × 1 0 5 N \leq 10^5, \ M \leq 2 \times 10^5 N≤105, M≤2×105
体节
0号操作只会对1号操作的范围造成影响,除此之外可以看作所有树都加了某一个点。
先假设所有操作都是针对所有树的。对每一个1号操作建立新的虚点,虚点连向操作改的那个点。生长的时候新的叶子连向上一次的虚点。
在操作只针对部分树的时候,先把所有虚点连向上一个虚点。将修改拆成左端点和右端点加一。将修改和询问按照树的编号排序。当进行到左端点的时候,将虚点的父亲连向实点;右端点把虚点的父亲连向上一个虚点。
讲的不清楚,直接看代码吧。。。
另:请注意,最后答案为:路径实点的数量-[LCA是虚点],可能要注意一下。
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
using namespace std;
const int Q=433333;
int si[Q],fa[Q],ls[Q],rs[Q],ct[Q];
void upd(int x)
{
si[x]=si[ls[x]]+si[rs[x]]+ct[x];
}
bool isroot(int x)
{return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
void xxx(int x)
{
int y=fa[x],z=fa[y];
if(ls[z]==y)ls[z]=x;
if(rs[z]==y)rs[z]=x;
if(ls[y]==x)ls[y]=rs[x],fa[ls[y]]=y,rs[x]=y;
else rs[y]=ls[x],fa[rs[y]]=y,ls[x]=y;
fa[x]=z,fa[y]=x;
upd(y),upd(x);
}
void splay(int x)
{
while(!isroot(x))
{
int y=fa[x],z=fa[y];
if(!isroot(y))
if((ls[z]==y&&ls[y]==x)||(rs[z]==y&&rs[y]==x))
xxx(y),xxx(x);
else xxx(x),xxx(x);
else xxx(x);
}
}
int AC(int x)
{
int t=0;
while(x)
{
splay(x);
rs[x]=t;
upd(x);
t=x;
x=fa[x];
}
return t;
}
void link(int x,int y)
{
splay(x);
fa[x]=y;
}
void cut(int x)
{
AC(x);
splay(x);
fa[ls[x]]=0;
ls[x]=0;
upd(x);
}
int maxq=0;
struct qu{
int tr,p,x,y;
}q[Q];
bool operator<(qu a,qu b)
{
return a.tr==b.tr?a.p<b.p:a.tr<b.tr;
}
int ans[Q],pt[Q];
int tre[Q];
int AL[Q],AR[Q];
int main()
{
int n,m,tot=2,lasroot=2;
int x,y,id,apr=1,v;
scanf("%d%d",&n,&m);
int OB=0;
tre[1]=1;
si[1]=ct[1]=1;
AL[1]=-1,AR[1]=998244353;
si[2]=ct[2]=0;
link(2,1);
for(int i=1;i<=m;i++)
{
scanf("%d",&id);
if(!id)
{
scanf("%d%d",&x,&y);
ct[++tot]=1;
si[tot]=1;
link(tot,lasroot);
tre[++apr]=tot;
AL[apr]=x,AR[apr]=y;
}
else if(id==1){
scanf("%d%d%d",&x,&y,&v);
x=max(x,AL[v]),y=min(y,AR[v]);
if(x>y)continue;
ct[++tot]=0;
si[tot]=0;
link(tot,lasroot);
q[++maxq]=(qu){x,i-m,tot,tre[v]};
q[++maxq]=(qu){y+1,i-m,tot,lasroot};
lasroot=tot;
}
else{
scanf("%d%d%d",&v,&x,&y);
q[++maxq]=(qu){v,i,tre[x],tre[y]},pt[i]=++OB;
}
}
sort(q+1,q+maxq+1);
for(int i=1;i<=maxq;i++)
{
x=q[i].x,y=q[i].y;
if(q[i].p>0)
{
id=pt[q[i].p];
AC(x);splay(x);
ans[id]+=si[x];
int t=AC(y);splay(y);
ans[id]+=si[y];
AC(t),splay(t);
ans[id]-=(si[t]<<1);
}
else{
cut(x);
link(x,y);
}
}
for(int i=1;i<=OB;i++)
printf("%d\n",ans[i]);
return 0;
}