P3258 [JLOI2014]松鼠的新家
考察:树上差分
思路:
点差分.区别在于中间点多+了1.注意不能在dfs前对差分数组-1.这样会导致递推错误.比如下图:
1 #include <iostream> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 const int N = 300050; 6 typedef long long LL; 7 int n,r[N],h[N],idx,d[N],depth[N],fa[N][20]; 8 struct Road{ 9 int fr,to,ne; 10 }road[N<<1]; 11 void add(int a,int b) 12 { 13 road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++; 14 } 15 void bfs(int s) 16 { 17 queue<int> q; 18 q.push(s); 19 memset(depth,0x3f,sizeof depth); 20 depth[s] = 1,depth[0] = 0; 21 while(q.size()) 22 { 23 int u = q.front(); 24 q.pop(); 25 for(int i=h[u];~i;i=road[i].ne) 26 { 27 int v = road[i].to; 28 if(depth[v]>depth[u]+1) 29 { 30 depth[v] = depth[u]+1; 31 q.push(v); 32 fa[v][0] = u; 33 for(int j=1;j<=19;j++) 34 fa[v][j] = fa[fa[v][j-1]][j-1]; 35 } 36 } 37 } 38 } 39 int lca(int a,int b) 40 { 41 if(depth[a]<depth[b]) swap(a,b); 42 for(int j=19;j>=0;j--) 43 if(depth[fa[a][j]]>=depth[b]) a = fa[a][j]; 44 if(a==b) return a; 45 for(int j=19;j>=0;j--) 46 if(fa[a][j]!=fa[b][j]) a = fa[a][j],b = fa[b][j]; 47 return fa[a][0]; 48 } 49 void dfs(int u,int fa) 50 { 51 for(int i=h[u];~i;i=road[i].ne) 52 { 53 int v = road[i].to; 54 if(v==fa) continue; 55 dfs(v,u); 56 d[u]+=d[v]; 57 } 58 } 59 int main() 60 { 61 scanf("%d",&n); 62 for(int i=1;i<=n;i++) scanf("%d",&r[i]),h[i] = -1; 63 for(int i=1;i<n;i++) 64 { 65 int a,b; scanf("%d%d",&a,&b); 66 add(a,b); add(b,a); 67 } 68 bfs(1); 69 for(int i=2;i<=n;i++) 70 { 71 int a = r[i-1],b = r[i]; 72 int anc = lca(a,b); 73 d[a]++,d[b]++,d[anc]--,d[fa[anc][0]]--; 74 } 75 dfs(1,-1); 76 for(int i=2;i<=n;i++) d[r[i]]--; 77 for(int i=1;i<=n;i++) printf("%d\n",d[i]); 78 return 0; 79 }