题目大意
有 k 棵树,每棵树有 n 个点,对于所有的点对 (s,t)(1≤s,t≤n),求出有多少个点在每棵树的 s 到 t 的链上都存在。
(以防表述不清,给一下传送门
n,k≤500
2s
题解
一开始怎么想都是 4 次方的复杂度,尝试了暴力+bitset 也 T 了。
这题的关键是要注意到一个性质:在一棵树上,x 到 y 经过 c,等价于 disx,y=disx,c+disc,y。
而且 disx,y 是小于等于 disx,c+disc,y 的。
那么 x 到 y 在所有树上都经过 c,就等价于 ∑disx,y=∑disx,c+∑disc,y。
那么就 O(kn2) 预处理 ∑disx,y,然后 O(n3) 枚举点对与中间点,判断合不合法。
代码
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(""); } }
|