0%

[CF1806E] Tree Master

服了,暴力没卡过去。

CF 评测姬好慢。

题目链接

题意

有一棵 个结点的树,点有点权,根是 。对于两个深度相等的节点 ,定义 ,特别地,。给出 次询问,每次询问

题解

考虑对于每一个询问,暴力找父亲,直到找到根。显然时间复杂度是 ,过不了。

但是如果加上一个记忆化,时间复杂度就对了。

证明

假设哈希表的时间复杂度为

设深度为 的节点个数为

时,时间复杂度为

因为 ,所以

时,时间复杂度为

因为 ,所以这样的 的数量不会超过 个。

时间复杂度为

还有一种不需要哈希表的方式:

对于每一个 的深度,我们进行记忆化,空间复杂度是

对于剩下的深度,我们暴力做,这种情况单次询问不会超过

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include<algorithm>
#include<iostream>
#include<cassert>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#define inf 0x3f3f3f3f3f3f3f3fll
using namespace std;
using ll=long long;
using ld=long double;
using pli=pair<ll,int>;
using pi=pair<int,int>;
template<typename A>
using vc=vector<A>;
inline int read()
{
int s=0,w=1;char ch;
while((ch=getchar())>'9'||ch<'0') if(ch=='-') w=-1;
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
template<const int N,const int M>
struct graph
{
int head[N+5];
int t[M+5];
int x[M+5];
int cntm;
graph(){ cntm=1;}
void clear(int n=N)
{
cntm=1;
for(int i=1;i<=n;i++) head[i]=0;
}
void ad(int u,int v)
{
cntm++;
t[cntm]=v;
x[cntm]=head[u];
head[u]=cntm;
}
void add(int u,int v)
{
ad(u,v);
ad(v,u);
}
int st(int num){ return head[num];}
int to(int num){ return t[num];}
int nx(int num){ return x[num];}
};
graph<100000,100000>g;
ll mem[100001][335];
vc<int>v[100001];
int dep[100001];
int id[100001];
int fa[100001];
int c[100001];
int a[100001];
int n,m;
int sq;
void dfs(int num)
{
id[num]=c[dep[num]]++,v[dep[num]].push_back(num);
for(int i=g.st(num);i;i=g.nx(i))
{
int p=g.to(i);
dep[p]=dep[num]+1;
dfs(p);
}
}
inline ll get(int x,int y)
{
if(c[dep[x]]<=sq&&mem[x][id[y]]) return mem[x][id[y]];
ll ans=get(fa[x],fa[y])+(ll)a[x]*a[y];
if(c[dep[x]]<=sq) mem[x][id[y]]=ans;
return ans;
}
int main()
{
n=read(),m=read();
for(;(sq+1)*(sq+1)<=n;sq++);
for(int i=1;i<=n;i++) a[i]=read();
for(int i=2;i<=n;i++) g.ad(fa[i]=read(),i);
dfs(1),mem[1][0]=(ll)a[1]*a[1];
for(int i=1;i<=m;i++)
{
int x=read(),y=read();
printf("%lld\n",get(x,y));
}
return 0;
}

感谢观看!