Description

奈特公司是一个巨大的情报公司,它有着庞大的情报网络。情报网络中共有\(n\)名情报员。每名情报员能有若干名(可能没有)下线,除\(1\)名大头目外其余\(n-1\)名情报员有且仅有\(1\)名上线。奈特公司纪律森严,每名情报员只能与自己的上、下线联系,同时,情报网络中任意两名情报员一定能够通过情报网络传递情报。

奈特公司每天会派发以下两种任务中的一个任务:

1.搜集情报:指派\(T\)号情报员搜集情报

2.传递情报:将一条情报从\(X\)号情报员传递给\(Y\)号情报员

情报员最初处于潜伏阶段,他们是相对安全的,我们认为此时所有情报员的危险值为\(0\);

一旦某个情报员开始搜集情报,他的危险值就会持续增加,每天增加1点危险值(开始搜集情报的当天危险值仍为\(0\),第\(2\)天危险值为\(1\),第\(3\)天危险值为\(2\),以此类推)。传递情报并不会使情报员的危险值增加。

为了保证传递情报的过程相对安全,每条情报都有一个风险控制值\(C\)。奈特公司认为,参与传递这条情报的所有情报员中,危险值大于\(C\)的情报员将对该条情报构成威胁。

现在,奈特公司希望知道,对于每个传递情报任务,参与传递的情报员有多少个,其中对该条情报构成威胁的情报员有多少个。

Input

第\(1\)行包含\(1\)个正整数\(n\),表示情报员个数。

笫\(2\)行包含\(n\)个非负整数,其中第\(i\)个整数\(Pi\)表示\(i\)号情报员上线的编号。特别地,若\(P_i=0\),表示\(i\)号情报员是大头目。

第\(3\)行包含\(1\)个正整数\(q\),表示奈特公司将派发\(q\)个任务(每天一个)。

随后\(q\)行,依次描述\(q\)个任务。

每行首先有\(1\)个正整数\(k\)。若\(k=1\),表示任务是传递情报,随后有3个正整数\(X_i、Y_i、C_i\),依次表示传递情报的起点、终点和风险控制值;

若\(k=2\),表示任务是搜集情报,随后有\(1\)个正整数\(T_i\),表示搜集情报的情报员编号。

Output

对于每个传递情报任务输出一行,应包含两个整数,分别是参与传递情报的情报员个数和对该条情报构成威胁的情报员个数。

输出的行数应等于传递情报任务的个数,每行仅包含两个整数,用一个空格隔开。输出不应包含多余的空行和空格。

Sample Input

7

0 1 1 2 2 3 3

6

1 4 7 0

2 1

2 4

2 7

1 4 7 1

1 4 7 3

Sample Output

5 0

5 2

5 1

HINT

\(n< = 2×10^5,Q< = 2×105,0< P_i,C_i< = N, 1< = T_i,X_i,Y_i< = n.\)

Solution

  • 第一问求\(LCA\),第二问对树上路径查询,显然先来一个树链剖分.
  • 考虑如何解决第二问.情报员第一次被指派时,给一个当前时间\(i\)作为权值.
  • 那么每次询问,若询问的时间为\(i\),则只需要询问路径上权值\(\leq i-C-1\)的点有多少个.使用树链剖分后,即为询问区间上某个数的排名.
  • 那么只需要维护一颗树套树即可(在线比较方便),外层可以选用树状数组,因为这里询问个数是可以直接用前缀和相减的.
#include<bits/stdc++.h>
const int inf=1e9;
using namespace std;
typedef long long LoveLive;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
{
fh=-1;
jp=getchar();
}
while (jp>='0'&&jp<='9')
{
out=out*10+jp-'0';
jp=getchar();
}
return out*fh;
}
const int MAXN=2e5+10;
int idx=0;
int x,y,z,r,p,q;
struct node{
int lson,rson,key,siz,weight;
}treap[MAXN*20];
struct FhqTreap{
int root;
FhqTreap()
{
treap[0].lson=treap[0].rson=treap[0].siz=0;
root=0;
}
#define rt treap[o]
#define ls treap[treap[o].lson]
#define rs treap[treap[o].rson]
inline int newnode(int key)
{
int o=++idx;
rt.lson=rt.rson=0;
rt.key=key;
rt.siz=1;
rt.weight=rand();
return o;
}
void pushup(int o)
{
rt.siz=ls.siz+rs.siz+1;
}
int BuildTree(int l,int r)
{
if(l>r)
return 0;
int mid=(l+r)>>1;
int o=newnode(inf);
rt.lson=BuildTree(l,mid-1);
rt.rson=BuildTree(mid+1,r);
pushup(o);
return o;
}
void split(int &x,int &y,int val,int o)
{
if(!o)
x=y=0;
else
{
if(val<rt.key)
{
y=o;
split(x,rt.lson,val,rt.lson);
}
else
{
x=o;
split(rt.rson,y,val,rt.rson);
}
pushup(o);
}
}
int merge(int X,int Y)
{
if(X==0 || Y==0)
return X+Y;
if(treap[X].weight<treap[Y].weight)
{
treap[X].rson=merge(treap[X].rson,Y);
pushup(X);
return X;
}
else
{
treap[Y].lson=merge(X,treap[Y].lson);
pushup(Y);
return Y;
}
}
void ins(int val)
{
int o=newnode(val);
root=merge(root,o);
}
int count(int lim)//<=lim
{
split(x,y,lim,root);
int res=treap[x].siz;
root=merge(x,y);
return res;
}
};
int n,m;
FhqTreap bit[MAXN];
#define lowbit(X) X&(-X)
void add(int X,int c)
{
for(;X<=n+1;X+=lowbit(X))
{
bit[X].ins(c);
}
}
int sum(int X,int lim)
{
int res=0;
for(;X;X-=lowbit(X))
res+=bit[X].count(lim);
return res;
}
int cnt=0,head[MAXN];
int nx[MAXN<<1],to[MAXN<<1];
inline void addedge(int u,int v)
{
++cnt;
to[cnt]=v;
nx[cnt]=head[u];
head[u]=cnt;
}
void insedge(int u,int v)
{
addedge(u,v);
addedge(v,u);
}
int dfn[MAXN],tid[MAXN],dfnidx=0;
int fa[MAXN],top[MAXN],dep[MAXN];
int siz[MAXN],mxson[MAXN];
void dfs1(int u,int Fa)
{
siz[u]=1;
fa[u]=Fa;
dep[u]=dep[Fa]+1;
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v!=Fa)
{
dfs1(v,u);
if(siz[v]>siz[mxson[u]])
mxson[u]=v;
siz[u]+=siz[v];
}
}
}
void dfs2(int u,int tp)
{
dfn[u]=++dfnidx;
tid[dfnidx]=u;
top[u]=tp;
if(mxson[u])
dfs2(mxson[u],tp);
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v!=fa[u] && v!=mxson[u])
dfs2(v,v);
}
}
int LCA(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
int query(int u,int v,int lim)
{
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
res+=sum(dfn[u],lim)-sum(dfn[top[u]]-1,lim);
u=fa[top[u]];
}
if(dep[u]<dep[v])
swap(u,v);
res+=sum(dfn[u],lim)-sum(dfn[v]-1,lim);
return res;
}
int vis[MAXN];
int main()
{
srand(time(NULL));
n=read();
int root;
for(int i=1;i<=n;++i)
{
int p=read();
if(!p)
root=i;
else
insedge(i,p);
}
dfs1(root,0);
dfs2(root,root);
m=read();
for(int i=1;i<=m;++i)
{
int op=read();
if(op==1)
{
int u=read(),v=read(),c=read();
int lca=LCA(u,v);
int ans1=dep[u]+dep[v]-2*dep[lca]+1;
int ans2=query(u,v,i-c-1);
printf("%d %d\n",ans1,ans2);
}
else
{
int t=read();
if(!vis[t])
{
add(dfn[t],i);
vis[t]=1;
}
}
}
return 0;
}
05-12 13:57