【十一联考 1】T2 树链剖分
算法思路就不说了,其实比较简单
这里讲一下坑点:
1.虽然我们可以将边权压到点上,但是当根不同时,差分数组显然不同。所以我们不能真的将边权看做点权,换根时还是要将其当做边权来考虑。
1.更新时,我们设dp[u]表示u节点为根时的最大价值,由于经过点u后,点v的儿子将变成点u,所以此时我们要更新点v的儿子中的最大值以及次大值。注意!不止要更新最大值,次大值也要正确维护
我的代码没有加优化,因为保证正确就不错了
#include<bits/stdc++.h>
using namespace std;
#define go(i,a,b) for(int i=a;i<=b;++i)
#define com(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define head(x) for(int i=head[x];i+1;i=e[i].nxt)
#define int long long
const int inf=0x3f3f3f3f3f3f3f3f,N=1e5+10,t=17;
int n,m,head[N],cnt,son[N],c[N],dep[N],f[N][20],mx[N],se[N],ans=0,dp[N];
struct edge{
int nxt,v;
}e[N*2];
void add(int u,int v){
e[cnt]=(edge){head[u],v};
head[u]=cnt++;
}
inline void read(int &x){
x=0;char f=1,c=getchar();
while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }
while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }
x*=f;
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;
f[u][0]=fa;
head(u){
int v=e[i].v;
if(v==fa) continue;
dfs(v,u);
}
}
int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
com(i,t,0){
if(dep[f[x][i]]>=dep[y]) x=f[x][i];
}
if(x==y) return x;
com(i,t,0){
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
}
return f[x][0];
}
void Dfs(int u,int fa){
head(u){
int v=e[i].v;
if(v==fa) continue;
Dfs(v,u);
c[u]+=c[v];
}
}
void DFS(int u,int fa){
head(u){
int v=e[i].v;
if(v==fa) continue;
DFS(v,u);
if(c[v]>=mx[u]){
se[u]=mx[u];
mx[u]=c[v];
}
else if(c[v]>se[u]) se[u]=c[v];
}
dp[1]+=mx[u];
}
void DFs(int u,int fa){
head(u){
int v=e[i].v;
if(v==fa) continue;
dp[v]=dp[u];
if(mx[u]==c[v]) dp[v]=dp[v]-mx[u]+se[u];
if(c[v]>=mx[v]){
dp[v]=dp[v]+c[v]-mx[v];
se[v]=mx[v];
mx[v]=c[v];
}
else if(c[v]>se[v]) se[v]=c[v];
DFs(v,u);
}
}
signed main(){
mem(head,-1);
read(n),read(m);
int u,v,Lca;
go(i,2,n){
read(u),read(v);
add(u,v),add(v,u);
}
dfs(1,0);
go(j,1,t)
go(i,1,n)
f[i][j]=f[f[i][j-1]][j-1];
while(m--){
read(u),read(v);
Lca=lca(u,v);
++c[u],++c[v];
c[Lca]-=2;
ans+=dep[u]+dep[v]-2*dep[Lca];
}
Dfs(1,0);
DFS(1,0);
DFs(1,0);
int tot=ans;
go(i,1,n)
ans=min(ans,tot-dp[i]);
printf("%lld",ans);
return 0;
}