洛谷 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代码:

 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 }
AC代码

 

posted @ 2020-08-05 22:06  dfydn  阅读(102)  评论(0编辑  收藏  举报