题面
题意是给你一棵树,在每个时刻标记一个点,或者问一条路径有多少个点在C时间前被标记了及路径长度。
这题好在可以离线,按时间排序后就取消了时间限制,操作变成标记一个点,询问就是问一条路径有几个点被标记了及路径长度。不会LCA,歧视树剖的我就水了棵LCT。
单点标记就把该点Splay到根,然后标记。
路径询问就分别Evert和Access两个端点,把路径放到一棵Splay上,在根上就可以得到这条路径的信息了。
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=200100;
int n,cnt,m;
int ans[N],len[N];
struct yy
{
int ops,num,tim,u,v;
}f[N];
bool cmp(yy x,yy y)
{
if(x.tim==y.tim)
return x.ops>y.ops;
return x.tim<y.tim;
}
struct tree
{
tree *c[2],*f,*pp;
int a,sum,siz;
bool flip;
int d(){return f->c[1]==this;}
void sc(tree *x,int d){(c[d]=x)->f=this;}
}nil[N],*ro[N];
tree *newtree()
{
nil[++cnt]=nil[0];
nil[cnt].siz=1;
return nil+cnt;
}
void up(tree *x)
{
x->sum=x->a+x->c[0]->sum+x->c[1]->sum;
x->siz=x->c[0]->siz+x->c[1]->siz+1;
}
void down(tree *x)
{
if(!x->flip)
return;
swap(x->c[0],x->c[1]);
if(x->c[0]!=nil) x->c[0]->flip^=1;
if(x->c[1]!=nil) x->c[1]->flip^=1;
x->flip=0;
}
void work(tree *x)
{
if(x->f!=nil)
work(x->f);
down(x);
}
void zig(tree *x)
{
tree *y=x->f;
int d=x->d();
y->sc(x->c[!d],d);
if(y->f==nil)
x->f=nil;
else
y->f->sc(x,y->d());
x->sc(y,!d);
up(y);
up(x);
x->pp=y->pp;
y->pp=nil;
}
void splay(tree *x)
{
work(x);
for(tree *y;x->f!=nil;)
{
y=x->f;
if(y->f!=nil)
(x->d() ^ y->d()) ? zig(x) : zig(y);
zig(x);
}
}
void Access(tree *x)
{
tree *y=nil;
while(x!=nil)
{
splay(x);
if(x->c[1]!=nil)
{
x->c[1]->f=nil;
x->c[1]->pp=x;
}
x->c[1]=y;
if(y!=nil)
y->f=x;
up(x);
y->pp=nil;
y=x;
x=x->pp;
}
}
void Evert(tree *x)
{
Access(x);
splay(x);
x->flip^=1;
}
int main()
{
nil->c[0]=nil->c[1]=nil->f=nil->pp=nil;
cin>>n;
for(int i=1;i<=n;i++)
ro[i]=newtree();
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x)
ro[i]->pp=ro[x];
}
cin>>m;
for(int i=1;i<=m;i++)
{
f[i].num=i;
scanf("%d",&f[i].ops);
if(f[i].ops==2)
{
scanf("%d",&f[i].u);
f[i].tim=i;
}
else
{
scanf("%d%d%d",&f[i].u,&f[i].v,&f[i].tim);
f[i].tim=i-f[i].tim-1;
}
}
sort(f+1,f+m+1,cmp);
for(int i=1;i<=m;i++)
{
if(f[i].ops==2)
{
splay(ro[f[i].u]);
ro[f[i].u]->a=1;
up(ro[f[i].u]);
}
else
{
Evert(ro[f[i].u]);
Access(ro[f[i].v]);
splay(ro[f[i].v]);
ans[f[i].num]=ro[f[i].v]->sum;
len[f[i].num]=ro[f[i].v]->siz;
}
}
for(int i=1;i<=m;i++)
if(len[i])
printf("%d %d\n",len[i],ans[i]);
return 0;
}