SCOI2015 情报传递
题目链接:戳我
树链剖分把树上问题转换成序列上的问题qwq,然后求链上小于i-k的节点个数。
可以离线做,先把所有操作读入,这样就不需要中间的修改了qwq
然后就是大力主席树了qwqwq
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#include<cmath>
#define MAXN 400010
using namespace std;
int n,m,tt,tot,root,cnt;
int head[MAXN<<1],fa[MAXN],st[MAXN],rt[MAXN],sum[MAXN<<4],lc[MAXN<<4],rc[MAXN<<4];
int dep[MAXN],top[MAXN],siz[MAXN],son[MAXN],id[MAXN];
struct Node{int u,v,k,op;}node[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
inline void add(int from,int to){edge[++tt].nxt=head[from],edge[tt].to=to,head[from]=tt;}
inline void insert(int &x,int f,int l,int r,int pos)
{
x=++tot;
//printf("x=%d p=%d l=%d r=%d pos=%d\n",x,f,l,r,pos);
lc[x]=lc[f],rc[x]=rc[f],sum[x]=sum[f]+1;
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) insert(lc[x],lc[f],l,mid,pos);
else insert(rc[x],rc[f],mid+1,r,pos);
}
inline int query(int l,int r,int ll,int rr,int k)
{
if(l==r) return sum[rr]-sum[ll];
int mid=(l+r)>>1;
if(k<=mid) return query(l,mid,lc[ll],lc[rr],k);
else return sum[lc[rr]]-sum[lc[ll]]+query(mid+1,r,rc[ll],rc[rr],k);
}
inline void build(int x)
{
insert(rt[x],rt[fa[x]],1,m,st[x]);
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
build(v);
}
}
inline void dfs1(int x)
{
siz[x]=1;
int maxx=-1;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
dep[v]=dep[x]+1;
dfs1(v);
siz[x]+=siz[v];
if(siz[v]>maxx) maxx=siz[v],son[x]=v;
}
}
inline void dfs2(int x,int topf)
{
top[x]=topf;
id[x]=++cnt;
if(son[x]) dfs2(son[x],topf);
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==son[x]) continue;
dfs2(v,v);
}
}
inline int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
if(dep[x]<dep[y]) return x;
else return y;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
freopen("ce.out","w",stdout);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&fa[i]);
if(fa[i]==0) root=i;
add(fa[i],i);
}
scanf("%d",&m);
for(int i=1;i<=n;i++) st[i]=m;
for(int i=1;i<=m;i++)
{
scanf("%d",&node[i].op);
if(node[i].op==1) scanf("%d%d%d",&node[i].u,&node[i].v,&node[i].k);
else scanf("%d",&node[i].u),st[node[i].u]=i;
}
dep[root]=1;
dfs1(root);
dfs2(root,root);
build(root);
//for(int i=1;i<=n;i++) printf("rt[%d]=%d\n",i,rt[i]); puts("");
//for(int i=1;i<=n;i++) printf("dep[%d]=%d\n",i,dep[i]); puts("");
//for(int i=1;i<=n;i++) printf("fa[%d]=%d\n",i,fa[i]);
for(int i=1;i<=m;i++)
{
int op=node[i].op,u,v,k;
if(op==1)
{
u=node[i].u,v=node[i].v,k=node[i].k;
int lca=LCA(u,v);
int cur_ans=0;
if(i-k<=1)
{
printf("%d 0\n",dep[u]+dep[v]-2*dep[lca]+1);
continue;
}
cur_ans+=query(1,m,rt[lca],rt[u],i-k-1);
cur_ans+=query(1,m,rt[lca],rt[v],i-k-1);
cur_ans+=(st[lca]<(i-k));
printf("%d %d\n",dep[u]+dep[v]-2*dep[lca]+1,cur_ans);
}
}
return 0;
}