cf519E

传送门

多组询问,问到树上两个点x,y距离相等的点的个数。

倍增求lca.

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<ctime>
const int maxn=1e5+299;
typedef long long LL;
using namespace std;
int n,m,ecnt,fir[maxn],nxt[maxn<<1],to[maxn<<1],f[maxn][21],R[maxn],sz[maxn];;
void add(int u,int v) {
    nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
    nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
}
void dfs(int x,int fa) {
    R[x]=R[fa]+1;
    f[x][0]=fa; 
    sz[x]=1;
    for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
        dfs(to[i],x);
        sz[x]+=sz[to[i]];
    }
}
void make_st() {
    for(int i=1;i<=20;i++)
        for(int j=1;j<=n;j++) 
            f[j][i]=f[f[j][i-1]][i-1];
}
int lca(int x,int y) {
    if(R[x]<R[y]) swap(x,y);
    for(int i=20;i>=0;i--) 
        if(R[f[x][i]]>=R[y]) x=f[x][i];
    if(x==y) return x;
    for(int i=20;i>=0;i--) 
        if(f[x][i]!=f[y][i]) {
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}
int cal(int x,int y) {
    if(x==y) return sz[1];
    int z=lca(x,y);
    if(R[x]==R[y]) {
        for(int i=20;i>=0;i--) 
            if(f[x][i]!=f[y][i]) {
            x=f[x][i];
            y=f[y][i];
            }
        return sz[1]-sz[x]-sz[y];
    }
    int l=R[x]-R[z]+R[y]-R[z];
    if(l&1) return 0; l>>=1;
    if(R[x]<R[y]) swap(x,y);
    l=R[x]-R[z]-l+1;
    for(int i=20;i>=0;i--) 
        if(R[f[x][i]]&&R[f[x][i]]-R[z]>=l)
            x=f[x][i];
    return sz[f[x][0]]-sz[x];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    dfs(1,0);
    make_st();
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",cal(x,y));
    }
    return 0;
}
View Code

 

posted @ 2017-10-02 21:41  啊宸  阅读(318)  评论(0编辑  收藏  举报