EOJ-A 昔我往矣(倍增LCA+乱搞)
题解:
既然只有5个点,那就无限乱搞,我的做法是不断取出当前点集两两之间的LCA插入点集,直到所有两两之间的LCA都已经在点集中了。
这一步的时间复杂度我感觉是一个调和级数,是可以被忽略的。
然后对每个点保存它的最深父亲,然后对点集建一棵树,对这棵树算边权贡献即可。
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; int n,q; struct node { int u,v,w,nxt; }edge[maxn<<1]; int head[maxn],tot; void addedge (int u,int v,int w) { edge[tot].u=u; edge[tot].v=v; edge[tot].w=w; edge[tot].nxt=head[u]; head[u]=tot++; edge[tot].u=v; edge[tot].v=u; edge[tot].w=w; edge[tot].nxt=head[v]; head[v]=tot++; } int father[30][maxn]; int h[maxn],d[maxn]; void dfs (int x) { for (int i=head[x];i!=-1;i=edge[i].nxt) { int v=edge[i].v; if (v==father[0][x]) continue; father[0][v]=x; h[v]=h[x]+1; d[v]=d[x]+edge[i].w; //printf("%d %d\n",v,h[v]); dfs(v); } } int lca (int x,int y) { if (h[x]<h[y]) swap(x,y); for (int i=20;i>=0;i--) if (h[x]-h[y]>>i) x=father[i][x]; if (x==y) return x; for (int i=20;i>=0;i--) if (father[i][x]!=father[i][y]) { x=father[i][x]; y=father[i][y]; } return father[0][x]; } int getDis (int x,int y) { return d[x]+d[y]-d[lca(x,y)]*2; } int getH (int x,int y) { return h[x]+h[y]-h[lca(x,y)]*2; } int x[maxn],ans,f[maxn]; vector<int> g[maxn]; void dfs1 (int x,int f) { for (int y:g[x]) { if (y==f) continue; ans+=getDis(x,y); dfs1(y,x); } } int main () { scanf("%d",&n); for (int i=1;i<=n;i++) head[i]=-1; for (int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); u++,v++; addedge(u,v,w); } h[1]=1; dfs(1); for (int i=1;i<=20;i++) for (int j=1;j<=n;j++) father[i][j]=father[i-1][father[i-1][j]]; scanf("%d",&q); while (q--) { for (int i=1;i<=5;i++) scanf("%d",x+i),x[i]++; int m=5; set<int> st; for (int i=1;i<=5;i++) { st.insert(x[i]); } while (1) { int f=1; for (int i=1;i<=m;i++) { for (int j=i+1;j<=m;j++) { int tt=lca(x[i],x[j]); if (!st.count(tt)) { st.insert(tt); x[++m]=tt; f=0; } } } if (f) break; } for (int i=1;i<=m;i++) f[x[i]]=0,g[x[i]].clear(); for (int i=1;i<=m;i++) { for (int j=i+1;j<=m;j++) { int tt=lca(x[i],x[j]); if (tt==x[i]) { if (h[x[i]]>h[f[x[j]]]) { f[x[j]]=x[i]; } } else if (tt==x[j]) { if (h[x[j]]>h[f[x[i]]]) { f[x[i]]=x[j]; } } } } int rt=0; for (int i=1;i<=m;i++) { //printf("%d %d\n",x[i],f[x[i]]); if (!f[x[i]]) { rt=x[i]; continue; } g[f[x[i]]].push_back(x[i]); } ans=0; dfs1(rt,0); printf("%d\n",ans); } }