洛谷 P3258 [JLOI2014]松鼠的新家(树上差分)
题目链接:https://www.luogu.com.cn/problem/P3258
对点差分:
sa[u]++; sa[v]++; sa[lca(u,v)]--; sa[f[lca(u,v)][0]]--;
对边差分:
sa[u]++; sa[v]++; sa[lca(u,v)]--;
注意这道题a[2]~a[n],它们既被作为前一段的终点,同时也是下一段的起点,所以每个点差分后会被多算一次,需要减掉。
AC代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=3*1e5+5; 7 int n,tot; 8 int head[N],dep[N],f[N][30],a[N],sa[N]; 9 struct node{ 10 int to,next; 11 }edge[N<<1]; 12 void init(){ 13 memset(head,-1,sizeof(head)); 14 } 15 void add(int u,int v){ 16 edge[tot].to=v; 17 edge[tot].next=head[u]; 18 head[u]=tot++; 19 } 20 void DFS(int u,int fa){ 21 f[u][0]=fa; 22 dep[u]=dep[fa]+1; 23 for(int i=1;(1<<i)<=dep[u];i++) f[u][i]=f[f[u][i-1]][i-1]; 24 for(int i=head[u];i!=-1;i=edge[i].next){ 25 int v=edge[i].to; 26 if(v==fa) continue; 27 DFS(v,u); 28 } 29 } 30 int lca(int u,int v){ 31 if(dep[u]<dep[v]) swap(u,v); 32 for(int i=20;i>=0;i--) if(dep[f[u][i]]>=dep[v]) u=f[u][i]; 33 if(u==v) return u; 34 for(int i=20;i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; 35 return f[u][0]; 36 } 37 void get_sa(int u,int fa){ 38 for(int i=head[u];i!=-1;i=edge[i].next){ 39 int v=edge[i].to; 40 if(v==fa) continue; 41 get_sa(v,u); 42 sa[u]+=sa[v]; 43 } 44 } 45 int main(){ 46 init(); 47 scanf("%d",&n); 48 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 49 for(int i=1;i<n;i++){ 50 int x,y; 51 scanf("%d%d",&x,&y); 52 add(x,y); add(y,x); 53 } 54 DFS(1,0); 55 for(int i=2;i<=n;i++){ 56 int u,v; 57 u=a[i-1],v=a[i]; 58 sa[u]++; 59 sa[v]++; 60 int x=lca(u,v); 61 sa[x]--; 62 sa[f[x][0]]--; 63 } 64 get_sa(1,0); 65 for(int i=2;i<=n;i++) sa[a[i]]--; 66 for(int i=1;i<=n;i++) printf("%d\n",sa[i]); 67 return 0; 68 }