本题当然可以用树剖解决,而且是树剖的模板题。但是对于本题来说,有一种更巧妙的办法
树上差分
类似于普通的差分,我们对于题目中的每一条路线i->j,把它拆成i->lca(i,j)->j.然后将i点、j点的权值加一,将lca(i,j)的权值减二
乍看起来没什么毛病,但是仔细想想,对lca(i,j)的子树进行前缀和,则lca(i,j)点的权值加二又减二,而题目要求lca(i,j)权值应当+1
所以我们将lca(i,j)的权值减一,将lca(i,j)的父亲的权值减一,这样就能符合题意了
差分之前预处理每个点的祖先,LCA+差分即可
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 typedef long long ll; 5 inline int read() { 6 int ret=0,f=1; 7 char c=getchar(); 8 while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();} 9 while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar(); 10 return ret*f; 11 } 12 using namespace std; 13 int n,k; 14 struct edge { 15 int next,to; 16 }a[50010<<1]; 17 int num,head[50010<<1]; 18 int sum[50010],ans; 19 int d[50010],fa[50010][31]; 20 inline void add(int from,int to) { 21 a[++num].next=head[from]; a[num].to=to; head[from]=num; 22 swap(from,to); 23 a[++num].next=head[from]; a[num].to=to; head[from]=num; 24 } 25 void find(int u,int f) { 26 d[u]=d[f]+1; 27 fa[u][0]=f; 28 for(int i=0;i<30;i++) fa[u][i+1]=fa[fa[u][i]][i]; 29 for(int i=head[u];i;i=a[i].next) { 30 int v=a[i].to; 31 if(v==f) continue ; 32 find(v,u); 33 } 34 } 35 int lca(int x,int y) { 36 if(d[x]<d[y]) swap(x,y); 37 for(int i=30;i>=0;i--) { 38 if(d[fa[x][i]]>=d[y]) x=fa[x][i]; 39 if(x==y) return x; 40 } 41 for(int i=30;i>=0;i--) 42 if(fa[x][i]!=fa[y][i]) { 43 x=fa[x][i]; 44 y=fa[y][i]; 45 } 46 return fa[x][0]; 47 } 48 void dfs(int u,int f) { 49 for(int i=head[u];i;i=a[i].next) { 50 int v=a[i].to; 51 if(v==f) continue ; 52 dfs(v,u); 53 sum[u]+=sum[v]; 54 } 55 ans=max(ans,sum[u]); 56 } 57 int main() { 58 n=read(); k=read(); 59 for(int i=1;i<n;i++) add(read(),read()); 60 find(1,0); 61 for(int i=1;i<=k;i++) { 62 int x=read(),y=read(); 63 sum[x]++; 64 sum[y]++; 65 int ret=lca(x,y); 66 sum[ret]--; 67 sum[fa[ret][0]]--; 68 } 69 dfs(1,0); 70 printf("%d ",ans); 71 return 0; 72 }