例题:
1. U92652 【模板】kruskal重构树
经典模板,非常重要
#include<bits/stdc++.h>
using namespace std;
const int N=6e5+10;
struct node{
int nex,to;
}e[N];
struct nodee{
int u,v,w;
}edge[N];
int n,m,q;
int f[N][20],fa[N],head[N],idx,cnt;
int d[N],val[N];
bool cmp(nodee x,nodee y){
return x.w<y.w;
}
int find(int x){
if(fa[x]==x) return fa[x];
return fa[x]=find(fa[x]);
}
void add(int u,int v){
e[++idx].nex=head[u];
e[idx].to=v;
head[u]=idx;
}
void dfs(int u){
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
d[v]=d[u]+1;
f[v][0]=u;
for(int k=1;k<=19;k++)
f[v][k]=f[f[v][k-1]][k-1];
dfs(v);
}
}
int lca(int u,int v){
if(d[u]<d[v]) swap(u,v);
for(int i=19;i>=0;i--)
if(d[f[u][i]]>=d[v])
u=f[u][i];
if(u==v) return u;
for(int i=19;i>=0;i--)
if(f[u][i]!=f[v][i]){
u=f[u][i];
v=f[v][i];
}
return f[u][0];
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=2*n;i++) fa[i]=i;
cnt=n;
for(int i=1;i<=m;i++){
int fu=find(edge[i].u),fv=find(edge[i].v);
if(fu==fv) continue;
cnt++;
fa[fu]=fa[fv]=cnt;
val[cnt]=edge[i].w;
add(cnt,fu); add(cnt,fv);
}
for(int i=1;i<=cnt;i++){
if(fa[i]==i){
d[i]=1;
dfs(i);
}
}
for(int i=1;i<=q;i++){
int u,v;
scanf("%d%d",&u,&v);
int fu=find(u),fv=find(v);
if(fu!=fv) printf("-1\n");
else printf("%d\n",val[lca(u,v)]);
}
return 0;
}
2. H. Life is a Game (2021 ICPC Shanghai)
此题重构出 树后
表示新加的点 所代表的边权值
表示 以 为根的子树所获得的能力值的总和
表示从 到它的 级祖先这条路径中,边权值 与 能都获得的能力值 的差值,取这个差值的最大值
maxnum[u][0]=val[f[u][0]]-sum[u];
for(int k=1;k<=19;k++){
f[u][k]=f[f[u][k-1]][k-1];
maxnum[u][k]=max(maxnum[u][k-1],maxnum[f[u][k-1]][k-1]);
}
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+10;
struct node{
int nex,to;
}e[N];
struct nodee{
int u,v,w;
}edge[N];
int head[N],idx,n,m,q,cnt;
int fa[N],f[N][20];
ll a[N],sum[N],val[N],maxnum[N][20];
//记录的是从 x 到它的 i 级祖先中,最大的边权 比 能够获得的能力值大多少
void add(int u,int v){
e[++idx].nex=head[u];
e[idx].to=v;
head[u]=idx;
}
int find(int x){
if(fa[x]==x) return fa[x];
return fa[x]=find(fa[x]);
}
bool cmp(nodee t1,nodee t2){
return t1.w<t2.w;
}
void KruskalTree(){
cnt=n;
sort(edge+1,edge+1+m,cmp);
for(int i=1;i<=2*n-1;i++) fa[i]=i;
for(int i=1;i<=m;i++){
int fu=find(edge[i].u),fv=find(edge[i].v);
if(fu!=fv){
cnt++;
fa[fu]=fa[fv]=cnt;
val[cnt]=edge[i].w;
add(cnt,fu); add(cnt,fv);
// printf("%d %d %d %d\n",cnt,fu,fv,edge[i].w);
if(cnt==2*n-1) break;
}
}
}
void dfs1(int u){
sum[u]+=a[u];
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
f[v][0]=u;
dfs1(v);
sum[u]+=sum[v];
}
}
void dfs2(int u){
maxnum[u][0]=val[f[u][0]]-sum[u];
for(int k=1;k<=19;k++){
f[u][k]=f[f[u][k-1]][k-1];
maxnum[u][k]=max(maxnum[u][k-1],maxnum[f[u][k-1]][k-1]);
}
for(int i=head[u];i;i=e[i].nex){
int v=e[i].to;
dfs2(v);
}
}
ll query(int x,int v){
for(int i=19;i>=0;i--)
if(f[x][i]&&maxnum[x][i]<=v)
x=f[x][i];
return sum[x]+v;
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w);
KruskalTree();
dfs1(cnt); dfs2(cnt);
// for(int i=1;i<=cnt;i++)
// printf("%d %d\n",i,sum[i]);
for(int i=1;i<=q;i++){
int x,v;
scanf("%d%d",&x,&v);
ll ans=query(x,v);
printf("%lld\n",ans);
}
return 0;
}