hdu 6031 Innumerable Ancestors (虚树 lca)

Posted darkroome

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 6031 Innumerable Ancestors (虚树 lca)相关的知识,希望对你有一定的参考价值。

hdu6031

一棵树(根节点是 1),给出两个集合,集合是 由树上的节点组成的。从两个集合中分别选一个元素,求出他们的 lca,问:lca 的深度最大是多少。

每个询问,两个集合,建虚树,然后dfs一遍,记录子树有没有A点、有没有B点,然后看既有A点又有B点的就更新深度到答案。

#include <bits/stdc++.h>
using namespace std;

const int maxN=100000+10;
const int maxM=100000+10;
const int max_log_n=21;

int n,m,Head[maxN],eg[maxM<<1],nxt[maxM<<1],tot=0;
void init() {
  memset(Head,0,sizeof(Head)); memset(eg,0,sizeof(eg)); memset(nxt,0,sizeof(nxt)); tot=0;
}
void addEdge(int u,int v) {
  eg[++tot]=v; nxt[tot]=Head[u]; Head[u]=tot;
  eg[++tot]=u; nxt[tot]=Head[v]; Head[v]=tot;
}

int id[maxN],dfsclock=0,pa[max_log_n][maxN],dep[maxN];
void dfs(int v,int fa) {
  id[v]=++dfsclock;
  int k=1;
  pa[0][v]=fa;
  dep[v]=fa==-1?1:dep[fa]+1;
  while(pa[k-1][v]!=-1) {
    pa[k][v]=pa[k-1][pa[k-1][v]];
    k++;
  }
  for(int i=Head[v];i;i=nxt[i]) {
    int u=eg[i];
    if(u!=fa) dfs(u,v);
  }
}

int getLca(int u,int v) {
  if(dep[u]>dep[v]) swap(u,v);
  for(int k=max_log_n-1;k>=0;k--) {
    if(((dep[v]-dep[u])>>k)&1) v=pa[k][v];
  }
  if(u==v) return u;
  for(int k=max_log_n-1;k>=0;k--) {
    if(pa[k][v]!=pa[k][u]) v=pa[k][v],u=pa[k][u];
  }
  return pa[0][v];
}

vector<int > As,Bs,all;
bool A[maxN],B[maxN];
bool cmp_by_id(int A,int B) {
  return id[A]<id[B];
}

vector<int > g[maxN];
bool recEg[maxN];
vector<int > used;
void new_addEdge(int u,int v) {
  g[u].push_back(v); g[v].push_back(u);
  if(!recEg[v]) used.push_back(v),recEg[v]=true;
  if(!recEg[u]) used.push_back(u),recEg[u]=true;
}

int stk[maxN],tp=0;

int ans=0;
bool havA[maxN],havB[maxN],vis[maxN];
void Recor(int v,int fa) {
  if(A[v]) havA[v]=true;
  if(B[v]) havB[v]=true;
  for(int i=0;i<(int)g[v].size();i++) {
    int u=g[v][i];
    if(u!=fa) Recor(u,v),havA[v]|=havA[u],havB[v]|=havB[u];
  }
  if(havA[v] && havB[v]) ans=max(ans,dep[v]);
}

int main() {
  int k,x;
  while(scanf("%d%d",&n,&m)==2) {
    init();
    memset(pa,-1,sizeof(pa)); memset(dep,0,sizeof(dep));
    memset(id,0,sizeof(id)); dfsclock=0;
    int u,v;
    for(int i=1;i<=n-1;i++) {
      scanf("%d%d",&u,&v);
      addEdge(u,v);
    }
    dfs(1,-1);
    for(int z=0;z<m;z++) {
      scanf("%d",&k);
      for(int i=1;i<=k;i++) {
        scanf("%d",&x);
        A[x]=true; As.push_back(x);
        if(!vis[x]) all.push_back(x);
        vis[x]=true;
      }
      scanf("%d",&k);
      for(int i=1;i<=k;i++) {
        scanf("%d",&x);
        B[x]=true; Bs.push_back(x);
        if(!vis[x]) all.push_back(x);
        vis[x]=true;
      }
      sort(all.begin(),all.end(),cmp_by_id);
      tp=0;
      stk[++tp]=1;
      for(int i=0;i<(int)all.size();i++) {
        int lca=getLca(stk[tp],all[i]);
        if(lca==stk[tp]) stk[++tp]=all[i];
        else {
          while(tp>=2 && dep[stk[tp-1]]>=dep[lca]) new_addEdge(stk[tp],stk[tp-1]),tp--;
          if(lca!=stk[tp]) new_addEdge(stk[tp],lca);
          tp--;
          stk[++tp]=lca; stk[++tp]=all[i];
        }
      }
      while(tp-1) new_addEdge(stk[tp],stk[tp-1]),tp--;

      ans=0;
      Recor(1,-1);
      printf("%d
",ans);

      for(int i=0;i<(int)As.size();i++) A[As[i]]=false;
      for(int i=0;i<(int)Bs.size();i++) B[Bs[i]]=false;
      As.clear(); Bs.clear();
      for(int i=0;i<(int)all.size();i++) vis[all[i]]=false;
      all.clear();

      for(int i=0;i<(int)used.size();i++) {
        recEg[used[i]]=false,g[used[i]].clear();
        havA[used[i]]=false,havB[used[i]]=false;
      }
      used.clear();
    }
  }
  return 0;
}

以上是关于hdu 6031 Innumerable Ancestors (虚树 lca)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 6031 Innumerable Ancestors

HDU 6031] Innumerable Ancestors

HDU6031 Innumerable Ancestors 倍增 - 题意详细概括 - 算法详解

hdu 3549 Flow Problem

LOJ #6031 字符串

禁止显示状态 警告 C6031 返回值被忽略: “scanf“.