拉力赛 题解 http://oj.fjaxyz.com:3389/problem.php?id=223 (LCA)
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; inline int read(){ int num=0,f=1; char c=getchar(); while(!isdigit(c)){if(c=='-') f=-1; c=getchar();} while(isdigit(c)){num=(num<<1)+(num<<3)+(c^48); c=getchar();} return num*f; } typedef long long ll; #define maxn 100010 int n,m,fa[maxn]; ll Ans[maxn],d[maxn]; bool vis[maxn]; vector<int>a[maxn],q[maxn],pa[maxn],nm[maxn]; vector<ll>b[maxn]; int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } inline int un(int a,int b){ int A=find(a),B=find(b); fa[A]=B; } void lca(int x,ll val){ vis[x]=1; d[x]=val; int num=a[x].size(); for(int i=0;i<num;i++){ int u=a[x][i]; if(!vis[u]){ lca(u,d[x]+b[x][i]); un(u,x); } } num=q[x].size(); for(int i=0;i<num;i++){ int e=q[x][i]; if(vis[e]){ int anc=find(e); int p=pa[x][i]; if(anc==p){ if(anc==x) Ans[nm[x][i]]=d[e]-d[x]; else Ans[nm[x][i]]=d[x]-d[e]; } else Ans[nm[x][i]]=-1; } } } int main(){ n=read(); m=read(); for(int i=1;i<=n-1;i++){ ll u,v,c; u=read(); v=read(); c=read(); a[u].push_back(v); a[v].push_back(u); b[u].push_back(c); b[v].push_back(c); } for(int i=1;i<=m;i++){ int x,y; x=read(); y=read(); q[x].push_back(y); q[y].push_back(x); pa[x].push_back(x);//记录最小节点(其实就是先输入的) pa[y].push_back(x); nm[x].push_back(i);//表示x和y是第几次询问(小技巧) nm[y].push_back(i); } for(int i=1;i<=n;i++) fa[i]=i; lca(1,0); ll sum=0,ans=0; for(int i=1;i<=m;i++){ if(Ans[i]!=-1){ ans+=Ans[i]; sum++; } } cout<<sum<<'\n'<<ans; } //9 3 //1 2 //1 3 //2 4 //2 5 //5 7 //5 8 //7 9 //3 6 //2 6 //9 7 //4 5