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与父亲连接的边被几条路径经过。

posted @ 2017-10-30 13:46  orzzz  阅读(161)  评论(0编辑  收藏  举报