codeforces D. Misha, Grisha and Underground(LCA)

 题目链接

D. Misha, Grisha and Underground

分析

LCA 模板题
对于三个顶点  a,b,c 因为,我们只需要找到他们的公共点,然后,公共点到各自距离子和的最大值就是ans
u公共点怎么找呢?三个顶点会产生3个LCA,一定有两个顶点的公共祖先是一样的,另外一个就是公共点,因此只需要对3个顶点异或一下就好了(还有这种操作~~~~)

AC code

http://codeforces.com/contest/832/submission/28877988

#include
#define pb push_back
#define mp make_pair
#define PI acos(-1)
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define ms(x,v) memset((x),(v),sizeof(x))
using namespace std;
const int MOD = 1e9+7;
const double eps = 1e-8;
typedef long long LL;
typedef long double DB;
typedef pair<int,int> PII;
const int maxn = 1e6+10;
const int MAX_V = 1e5+10;
std::vector<int> G[maxn];

const int LOG_V = 20;
int n;
int root=1;//树根
int par[MAX_V][LOG_V];//每一个节点的(2^k)个祖先
int depth[MAX_V];
  //找节点的深度和父亲.
  void dfs(int v,int p,int d){
    par[v][0] = p;
    depth[v] = d;
    for(int i=0 ; iif(G[v][i]!=p)dfs(G[v][i],v,d+1);//这是树,边的关系只有父亲节点和子孙.
  }
  //预处理,倍增
  void init(){
      //ms(par,-1);
    dfs(root,-1,0);
    for(int k = 0 ; k1 ; ++k){//过剩处理不影响结果.
      for(int i = 1 ; i<=n ; ++i)
      par[i][k+1] = par[i][k] ==-1?-1 :par[par[i][k]][k];
    }

  }

  int lca(int u,int v){
    //跑到同一高度.
    if(depth[u]>depth[v])swap(u,v);
    for(int k=0 ; kif(((depth[v]-depth[u])>>k) & 1)//差的二进制走
        v = par[v][k];
    if(u==v)return u;
    for(int k= LOG_V-1 ; k>=0 ; k--)
      if(par[u][k]!=par[v][k]){//避免跳过最近祖先
        u = par[u][k];
        v = par[v][k];
      }
    return par[u][0];
  }
int dis(int u,int v){
    return depth[u] + depth[v] - 2* depth[lca(u,v)];
}
void add_edge(int u,int v) {
    G[u].pb(v);G[v].pb(u);
}
int main() {

    std::ios::sync_with_stdio(false);
    std::cin.tie(0);

    int q;
    cin>>n>>q;
    for(int i=0 ; i1 ; ++i){
        int p;cin>>p;
        add_edge(i+2,p);
    }

    init();

    while (q--) {
        int a,b,c;
        cin>>a>>b>>c;
        int v1 = lca(a,b);
        int v2 = lca(a,c);
        int v3 = lca(b,c);
        // std::cout << v1 <<" " <
        int v = v1 ^v2 ^v3;
        std::cout << max({dis(v,a),dis(v,b),dis(v,c)})+1 << '\n';
    }


    return 0;
}

总结

LCA 的模板居然出现问题了,让我找了好一会儿~,,,,

for(int k = 0 ; k1 ; ++k){//过剩处理不影响结果.
      for(int i = 1 ; i<=n ; ++i)
      par[i][k+1] = par[i][k] ==-1?-1 :par[par[i][k]][k];
    }

啊当这个k超出范围的时候,由于二位数组是一块连续内存,所以第一个元素会被溢出的元素修改掉

你可能感兴趣的:(算法刷题)