题目链接:https://www.luogu.com.cn/problem/CF191C
https://codeforces.com/problemset/problem/191/C
题意:
给你一棵树,然后给你m对点,将每对点之间的最短路径上每条边权值+1,求操作完成后每条边的权值。
方法:
p[s]++,p[t]++,p[lca(s,t)]-=2
用倍增算法计算LCA
代码:
#include <bits/stdc++.h> #define LL long long using namespace std; const int maxn=100000+10; int lg[maxn]; int n; struct Edge{ int to, next; }e[maxn<<1]; int head[maxn]; int en; int fa[maxn][22]; int depth[maxn]; int u[maxn]; int v[maxn]; int cf[maxn]; void addEdge(int from, int to){ e[en].next=head[from]; e[en].to=to; head[from]=en; ++en; } void dfs(int cur, int pre){ depth[cur]=depth[pre]+1; fa[cur][0]=pre; for(int i=1;i<=lg[depth[cur]-1];++i){ fa[cur][i]=fa[fa[cur][i-1]][i-1]; } for(int i=head[cur];i!=-1;i=e[i].next){ int v=e[i].to; if(v!=pre){ dfs(v,cur); } } } int lca(int a, int b){ if(depth[a]<depth[b]) swap(a,b); while(depth[a]>depth[b]){ a=fa[a][lg[depth[a]-depth[b]]]; } if(a==b) return a; for(int i=lg[depth[a]];i>=0;--i){ if(fa[a][i]!=fa[b][i]){ a=fa[a][i]; b=fa[b][i]; } } return fa[a][0]; } void dfs2(int cur, int pre){ for(int i=head[cur];i!=-1;i=e[i].next){ int ve=e[i].to; if(ve!=pre){ dfs2(ve,cur); cf[cur]+=cf[ve]; } } } int main(){ memset(head,-1,sizeof(head)); scanf("%d", &n); lg[1]=0; lg[2]=1; for(int i=3;i<=n;++i){ if(i==(1<<(lg[i-1]+1))){ lg[i]=lg[i-1]+1; }else{ lg[i]=lg[i-1]; } } for(int i=1;i<=n-1;++i){ scanf("%d %d", &u[i], &v[i]); addEdge(u[i],v[i]); addEdge(v[i],u[i]); } dfs(1,0); int k; scanf("%d", &k); for(int i=1;i<=k;++i){ int a,b; scanf("%d %d", &a, &b); int c=lca(a,b); ++cf[a]; ++cf[b]; cf[c]-=2; } dfs2(1,0); for(int i=1;i<=n-1;++i){ if(depth[u[i]]>depth[v[i]]){ printf("%d ", cf[u[i]]); }else { printf("%d ", cf[v[i]]); } } return 0; }
参考:
https://www.luogu.com.cn/blog/eps/cf191fools-and-roads