题目链接
https://www.luogu.com.cn/problem/P3128
解题思路
树上差分
LCA
知道树上差分在什么情况下使用,树上路径,树上两点等。
AC代码
#include<bits/stdc++.h> using namespace std; const int N=5e4+10; const int INF=0x3f3f3f3f; vector<int> e[N]; int n,k,a,b,ans=-INF,Time; int sum[N],path[N<<1],st[N<<1][20],pos[N<<1][20],dp[N],in[N],fa[N],d[N]; void dfs(int x,int father,int deep) { path[++Time]=x; fa[x]=father; if(dp[x]==0) dp[x]=deep; if(in[x]==0) in[x]=Time; for(int i=0;i<e[x].size();i++) { if(father==e[x][i]) continue; dfs(e[x][i],x,deep+1); path[++Time]=x; } } void ST()//建立ST表 { for(int i=1;i<=Time;i++) st[i][0]=dp[path[i]],pos[i][0]=i; for(int j=1;(1<<j)<=Time;j++) for(int i=1;i+(1<<j-1)-1<=Time;i++) if(st[i][j-1]<st[i+(1<<j-1)][j-1]) st[i][j]=st[i][j-1],pos[i][j]=pos[i][j-1]; else st[i][j]=st[i+(1<<j-1)][j-1],pos[i][j]=pos[i+(1<<j-1)][j-1]; } int LCA(int x,int y)//求最近公共祖先 { int tx=in[x],ty=in[y]; if(tx>ty) swap(tx,ty); int k=0;while(tx+(1<<k+1)-1<=ty) k++; return st[tx][k]<st[ty-(1<<k)+1][k]?path[pos[tx][k]]:path[pos[ty-(1<<k)+1][k]]; } int dfss(int x,int fa)//递归求和,确定每个节点的值 { if(sum[x]!=INF) return sum[x]; sum[x]=d[x]; for(int i=0;i<e[x].size();i++) { if(fa==e[x][i]) continue; sum[x]+=dfss(e[x][i],x); } ans=max(sum[x],ans); return sum[x]; } int main() { memset(sum,0x3f,sizeof sum); cin>>n>>k; for(int i=1;i<n;i++) { cin>>a>>b; e[a].push_back(b); e[b].push_back(a); } dfs(1,0,1); ST(); while(k--) { cin>>a>>b; int c=LCA(a,b); d[a]++; d[b]++; d[c]--; d[fa[c]]--; } dfss(1,0);//假设1号节点为根 cout<<ans<<endl; return 0; }