题目大意:
维护一颗树,支持一下操作(可以离线)
1、给一个点赋值;
2、查询一条链上比有多少个点以及某个数(i-c)小的点有多少个。
(我这个题目大意略精简了一点哈=。=,但是还是可以比较轻松的把原题目转化成这个意思的)
题目分析:
我们可以把所有的操作离线出来,把赋值操作按照赋值的大小排序(相当于没排,不知道我这个沙茶为毛要排一下>_<)
然后把所有的询问按照要(i-c)从小到大排序。
树链剖分一下,用树状数组维护dfs序。
扫一遍所有的询问,把小于询问权值的赋值操作的位置在dfs序中改为1。
然后查询树链上1的个数就可以了。
时间复杂度O(mlog^2n)
代码如下:
#include <cstdio>
#include <algorithm>
#include <iostream>
#define N 220000
using namespace std;
inline int lowbit(int x){ return x&-x; }
int n,m,root,sum,cnt;
int fir[N],nes[N],v[N],tot=1;
int fa[N],dep[N],son[N],sz[N],pos[N],ld[N],top;
int fw[N],ans[N],_ans[N];
bool mark[N];
struct Change{
int x,id;
bool operator < (const Change &c) const { return id<c.id; }
}a[N];
struct Query{
int x,y,c,id;
bool operator < (const Query &a) const { return c<a.c; }
}q[N];
void edge(int x,int y)
{
v[++tot]=y;
nes[tot]=fir[x];
fir[x]=tot;
}
void update(int x)
{
for(;x<=n;x+=lowbit(x))
fw[x]++;
}
int query(int l,int r)
{
int ans=0;
for(;r;r-=lowbit(r))
ans+=fw[r];
for(l--;l;l-=lowbit(l))
ans-=fw[l];
return ans;
}
void dfs1(int c)
{
dep[c]=dep[fa[c]]+1;
sz[c]=1; son[c]=0;
for(int t=fir[c];t;t=nes[t])
{
dfs1(v[t]);
sz[c]+=sz[v[t]];
if(sz[v[t]]>sz[son[c]]) son[c]=v[t];
}
}
void dfs2(int c)
{
pos[c]=++top;
ld[c]=c;
if(son[fa[c]]==c) ld[c]=ld[fa[c]];
if(son[c]) dfs2(son[c]);
for(int t=fir[c];t;t=nes[t])
{
if(v[t]==son[c]) continue;
dfs2(v[t]);
}
}
void solve(int c)
{
int x=q[c].x,y=q[c].y;
int id=q[c].id;
while(ld[x]!=ld[y])
{
if(dep[ld[x]]<dep[ld[y]]) swap(x,y);
ans[id]+=pos[x]-pos[ld[x]]+1;
_ans[id]+=query(pos[ld[x]],pos[x]);
x=fa[ld[x]];
}
if(dep[x]<dep[y]) swap(x,y);
ans[id]+=pos[x]-pos[y]+1;
_ans[id]+=query(pos[y],pos[x]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&fa[i]);
if(fa[i]==0) root=i;
else edge(fa[i],i);
}
dfs1(root); dfs2(root);
scanf("%d",&m);
for(int i=1,opt,x,y,z;i<=m;i++)
{
scanf("%d",&opt);
if(opt==1)
{
cnt++;
scanf("%d%d%d",&q[cnt].x,&q[cnt].y,&q[cnt].c);
q[cnt].id=cnt;
q[cnt].c=i-q[cnt].c;
}
else
{
scanf("%d",&x);
if(!mark[x])
{
sum++;
if(!mark[x]) mark[x]=true;
a[sum].x=x; a[sum].id=i;
}
}
}
sort(a+1,a+sum+1);
sort(q+1,q+cnt+1);
int now=1;
for(int i=1;i<=cnt;i++)
{
while(now<=sum && a[now].id<q[i].c) update(pos[a[now].x]),now++;
solve(i);
}
for(int i=1;i<=cnt;i++) printf("%d %d\n",ans[i],_ans[i]);
return 0;
}