把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P5384 [Cnoi2019]雪松果树

题面传送门
显然线段树合并\(O(nlogn)\)可惜被卡了。
我们考虑另外一种写法。
首先对于每个点要求\(k\)级祖先。因为没有强制在线所以不用长链剖分,直接树上dfs一边然后开栈存储即可。
再将每个询问挂在\(k\)级祖先上再dfs一遍,这一次对于每个询问,减掉遍历子树前的答案,加上遍历子树后的答案就是子树内的答案。
注意没有\(k\)级祖先输出\(0\)。这样时间复杂度就是\(O(n)\)了。
code:

#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 1000000
#define M 50
#define W (1<<20)
#define mod 1000000007
#define eps (1e-7)
#define U unsigned int
#define IT set<ques>::iterator
using namespace std;
int n,m,k,x,y,z,st[N+5],sh,ans[N+5],f[N+5],d[N+5],A[N+5],B[N+5];
struct ques{int num,x;}now;vector<ques>Q[N+5];
struct yyy{int to,z;};
struct ljb{
	int head,h[N+5];yyy f[N+5];
	inline void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;}
}s;
I void dfs(int x,int last){
	st[++sh]=x;yyy tmp;d[x]=d[last]+1;
	for(int i=0;i<Q[x].size();i++)now=Q[x][i],A[now.num]=(sh-now.x>0?st[sh-now.x]:0);
	for(int i=s.h[x];i;i=tmp.z)tmp=s.f[i],dfs(tmp.to,x);sh--;
}
I void Make(int x){
	for(int i=0;i<Q[x].size();i++)now=Q[x][i],ans[now.num]-=f[now.x]+1; 
	f[d[x]]++;yyy tmp;for(int i=s.h[x];i;i=tmp.z)tmp=s.f[i],Make(tmp.to);
	for(int i=0;i<Q[x].size();i++) now=Q[x][i],ans[now.num]+=f[now.x];
}
static char buf[10000000],*p1=buf,*p2=buf;
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++
I void read(int &x){
	char s=getchar();x=0;
	while(s<'0'||s>'9') s=getchar();
	while(s>='0'&&s<='9') x=x*10+s-48,s=getchar();
}
I void print(int x){if(x>9) print(x/10);putchar(x%10+48);}
int main(){
	freopen("1.in","r",stdin);
	re int i,j;scanf("%d%d",&n,&m);for(i=2;i<=n;i++) read(x),s.add(x,i);
	for(i=1;i<=m;i++) read(A[i]),read(B[i]),Q[A[i]].push_back((ques){i,B[i]});dfs(1,0);for(i=1;i<=n;i++) Q[i].clear();
	for(i=1;i<=m;i++) A[i]&&(Q[A[i]].push_back((ques){i,B[i]+d[A[i]]}),0);
    Make(1);/*for(i=1;i<=n;i++) f[i]+=f[i-1];*/for(i=1;i<=n;i++) (!A[i])&&(ans[i]=0);
    for(i=1;i<=m;i++) printf("%d ",ans[i]); 	
}
posted @ 2021-06-19 21:52  275307894a  阅读(59)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end