[10.2模拟] tree

题意:给你一棵树,m次询问,每次询问(a,b),即a和b是否在一条链上

题解:

树上倍增

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define RG register
#define N 200010
using namespace std;

int n,qu,e_num;
int nxt[N*2],to[N*2],h[N],siz[N],dep[N],fa[N][22];

inline int gi() {
  int x=0,o=1; char ch=getchar();
  while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
  if(ch=='-') o=-1,ch=getchar();
  while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
  return o*x;
}

inline void add(int x, int y) {
  nxt[++e_num]=h[x],to[e_num]=y,h[x]=e_num;
}

inline int find(int y, int x) {
  for(int j=20; j>=0; j--) {
    if(dep[fa[y][j]]>dep[x] && fa[y][j]) y=fa[y][j];
  }
  return y;
}

inline void dfs(int u) {
  siz[u]=1;
  for(int i=h[u]; i; i=nxt[i]) {
    int v=to[i];
    if(v==fa[u][0]) continue;
    fa[v][0]=u,dep[v]=dep[u]+1;
    dfs(v);
    siz[u]+=siz[v];
  }
}

int main() {
  n=gi(),qu=gi();
  for(RG int i=1; i<n; i++) {
    int x=gi(),y=gi();
    add(x,y),add(y,x);
  }
  dep[1]=1;
  dfs(1);
  for(int j=1; j<=20; j++)
    for(int i=1; i<=n; i++)
      fa[i][j]=fa[fa[i][j-1]][j-1];
  for(int i=1; i<=qu; i++) {
    int x=gi(),y=gi(),z;
    if(dep[x]>dep[y]) swap(x,y);
    z=find(y,x);
    if(fa[z][0]!=x) printf("%d\n", siz[x]+siz[y]);
    else printf("%d\n", siz[y]+n-siz[z]);
  }
  return 0;
}

posted @ 2017-10-04 08:52  HLX_Y  阅读(104)  评论(0编辑  收藏  举报