【VKOSHP 19 L】Time Travel 题解

题目大意

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

题解

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

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

  那么就 O(kn2)O(kn^2) 预处理 disx,y\sum dis_{x,y},然后 O(n3)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("");
}
}