【VKOSHP 19 L】Time Travel 题解

题目大意

  有 $k$ 棵树,每棵树有 $n$ 个点,对于所有的点对 $(s,t)$($1 \leq s,t \leq n$),求出有多少个点在每棵树的 $s$ 到 $t$ 的链上都存在。
  (以防表述不清,给一下传送门
  $n,k \leq 500$
  2s

题解

  一开始怎么想都是 4 次方的复杂度,尝试了暴力+bitset 也 T 了。

  这题的关键是要注意到一个性质:在一棵树上,$x$ 到 $y$ 经过 $c$,等价于 $dis_{x,y}=dis_{x,c}+dis_{c,y}$。
  而且 $dis_{x,y}$ 是小于等于 $dis_{x,c}+dis_{c,y}$ 的。
  那么 $x$ 到 $y$ 在所有树上都经过 $c$,就等价于 $\sum dis_{x,y}=\sum dis_{x,c}+\sum dis_{c,y}$。

  那么就 $O(kn^2)$ 预处理 $\sum dis_{x,y}$,然后 $O(n^3)$ 枚举点对与中间点,判断合不合法。

代码

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
#include<bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

const int maxn=505;

int n,k;

int tot[maxn],go[maxn][2*maxn],nxt[maxn][2*maxn],f1[maxn][maxn];
void ins(int ty,int x,int y)
{
go[ty][++tot[ty]]=y;
nxt[ty][tot[ty]]=f1[ty][x];
f1[ty][x]=tot[ty];
}

int dis[maxn][maxn];
void dfs(int ty,int tp,int k,int last,int s)
{
dis[tp][k]+=s;
for(int p=f1[ty][k]; p; p=nxt[ty][p]) if (go[ty][p]!=last) dfs(ty,tp,go[ty][p],k,s+1);
}

int main()
{
scanf("%d %d",&n,&k);
fo(i,1,k)
fo(j,1,n-1)
{
int x,y;
scanf("%d %d",&x,&y);
ins(i,x,y), ins(i,y,x);
}

fo(i,1,k)
fo(j,1,n) dfs(i,j,j,0,0);

fo(a,1,n)
{
fo(b,1,n)
{
int sum=0;
fo(c,1,n) sum+=(dis[a][c]+dis[c][b]==dis[a][b]);
printf("%d ",sum);
}
puts("");
}
}