CF#196B http://codeforces.com/contest/338/problem/B
题意:在一颗树上,给m个点,求到所有m个点距离不超过d的点的个数,所有路径长度为1。
分析:问题转化,就是求一个点是否到离它最远的给定点的距离小于d,
先第一遍dfs1求出以当前节点u为根的子树到子树中离它最远的给定点的距离d1[u],和次远的距离d2[u],
并且记录下最远距离是从哪个son转移过来的,fo[u];
第二遍dfs2求出当前节点从它fa出发能碰到给定点的最远距离up[u],那么对于当前点u,max(d1[u],up[u]),就是u到
所有给定点的最远的距离;
up[]的可以按照dfs的顺序递推求出,假设我们已经求出up[c1],现在求up[c2]
up[c2]表示从c2的fa结点也就是c1那边给定结点(红色圆点)到c2的最远距离
那么up[c2] 由两部分转移过来,一个是原先以c1为根的子树除去c2的分支后的最远距离,这就是为什么要记录最远是从哪个son转移过来
dd = (fo[c1] == c2 ? d2[c1] : d1[c1]);
还有就是up[c1];显然up[c2] = max(dd,up[c1])+1;(up[c1]表示从c6那边转移过来的值)
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<iostream> 5 #include<algorithm> 6 #include<vector> 7 #include<cmath> 8 #define pbk push_back 9 using namespace std; 10 const int N = 100000+10; 11 const int INF = 1000000+10; 12 vector<int> g[N]; 13 int n,m,d; 14 bool p[N]; 15 int d1[N],d2[N],fo[N],up[N]; 16 int co[N]; 17 void update(int c,int rt,int x,int &m1,int &m2) { 18 if (x >= m1) { 19 m2 = m1; m1 = x; 20 fo[rt] = c; 21 }else if (x < m1) { 22 if (x > m2) m2 = x; 23 } 24 } 25 void dfs1(int rt,int fa) { 26 int sz = g[rt].size(); 27 d1[rt] = d2[rt] = -INF; 28 for (int i = 0; i < sz; i++) { 29 int c = g[rt][i]; 30 if (c == fa) continue; 31 dfs1(c,rt); 32 if (co[c]) { 33 update(c,rt,d1[c]+1,d1[rt],d2[rt]); 34 co[rt] = 1; 35 } 36 } 37 if (p[rt]) { 38 if (d1[rt] > 0 && d2[rt] < 0) d2[rt] = 0; 39 if (d1[rt] < 0) { 40 d1[rt] = 0; fo[rt] = rt; 41 } 42 co[rt] = 1; 43 } 44 } 45 void dfs2(int rt,int fa) { 46 int sz = g[rt].size(); 47 for (int i = 0; i < sz; i++) { 48 int c = g[rt][i]; 49 if (c == fa) continue; 50 int dd = (fo[rt] == c ? d2[rt] : d1[rt]); 51 up[c] = max(dd, up[rt]) + 1; 52 dfs2(c,rt); 53 } 54 } 55 void solve(){ 56 memset(co,0,sizeof(co)); 57 memset(fo,-1,sizeof(fo)); 58 dfs1(1,-1); 59 up[1] = -INF; 60 dfs2(1,-1); 61 62 int ans = 0; 63 for (int i = 1; i <= n; i++) { 64 if (d1[i] <= d && up[i] <= d) ans++; 65 } 66 printf("%d\n",ans); 67 } 68 int main(){ 69 while (~scanf("%d%d%d",&n,&m,&d)) { 70 memset(p,0,sizeof(p)); 71 for (int i = 0; i < m; i++) { 72 int f; scanf("%d",&f); 73 p[f] = 1; 74 } 75 for (int i = 0; i <= n; i++) g[i].clear(); 76 for (int i = 0; i < n-1; i++) { 77 int u,v; scanf("%d%d",&u,&v); 78 g[u].pbk(v); g[v].pbk(u); 79 } 80 solve(); 81 } 82 return 0; 83 }