给定一个的树,已经次操作,每次操作会选择两个点和,使得两点路径上所有的点都加,求点权的最大值。
直接暴力是的,这里考虑差分最后再求前缀和。树上的差分分为点差分和边差分,这里是点差分。对分别,然后对和分别,最后一遍处理即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=5e4+7;
vector<int> G[N];
int fa[N][18],dep[N];
int cnt[N];
void dfs1(int u,int f) {
dep[u]=dep[f]+1;
fa[u][0]=f;
for(int i=1;(1<<i)<=dep[u];i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(auto &v:G[u]) {
if(v==f) continue;
dfs1(v,u);
}
}
int lca(int x,int y) {
if(dep[x]<dep[y]) swap(x,y);
for(int i=17;i>=0;i--) {
if((1<<i)<=dep[x]-dep[y])
x=fa[x][i];
}
if(x==y) return x;
for(int i=17;i>=0;i--) {
if(fa[x][i]!=fa[y][i]) {
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
int ans=0;
void dfs2(int u,int fa) {
for(auto &v:G[u]) {
if(v==fa) continue;
dfs2(v,u);
cnt[u]+=cnt[v];
}
ans=max(ans,cnt[u]);
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++) {
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,0);
while(m--) {
int u,v;
scanf("%d%d",&u,&v);
cnt[u]++;
cnt[v]++;
int LCA=lca(u,v);
cnt[LCA]--;
cnt[fa[LCA][0]]--;
}
dfs2(1,0);
printf("%d\n",ans);
return 0;
}
来源:https://blog.csdn.net/qq_40859782/article/details/100165885