LCA模板
noip之前再熟一下板子吧,,,LCA好久(从来)没敲过了。。。
#include<bits/stdc++.h> using namespace std; const int N=500010; const int inf=0x3f3f3f3f; inline int read(){ int r=0,c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c)) r=r*10+c-'0',c=getchar(); return r; } struct Edge{ int to,nxt; }e[N*2]; int head[N],cnt=1; void add(int u,int v){ e[cnt]=(Edge){v,head[u]}; head[u]=cnt++; } int n,m,S,d[N]; int p[N][22]; void dfs(int u,int fa){ p[u][0]=fa; for(int i=1;i<=20;i++) p[u][i]=p[p[u][i-1]][i-1]; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(v==fa)continue; d[v]=d[u]+1;dfs(v,u); } } int lca(int u,int v){ if(d[u]<d[v])swap(u,v); for(int i=20;~i;i--) if(d[p[u][i]]>=d[v])u=p[u][i]; if(u==v)return u; for(int i=20;~i;i--) if(p[u][i]^p[v][i]) u=p[u][i],v=p[v][i]; return p[u][0]; } void init(){ n=read();m=read();S=read(); for(int i=1;i<n;i++){ int u=read(),v=read(); add(u,v);add(v,u); } d[S]=1;dfs(S,0); } void solve(){ while(m--){ int u=read(),v=read(); printf("%d\n",lca(u,v)); } } int main(){ init(); solve(); }
树上差分:
设路径的起点为$x$,终点为$y$。差分数组为$c$。
如果是修改点,则$c[x]++,c[y]++,c[lca(x,y)]--,c[fa[lca(x,y)]]--$。
如果是修改边,则$c[x]++,c[y]++,c[lca(x,y)]-=2$。
转移后($c[u]+=\sum c[v],v\in u$)
修改点,$c[i]$表示i被几条路径经过。
修改边,$c[i]$表示i与父亲连接的边被几条路径经过。