Codeforces 832D. Misha, Grisha and Underground【LCA】

来源:互联网 发布:预算软件有哪些 编辑:程序博客网 时间:2024/06/06 03:30

题意:已知一棵树节点数n,n-1 条边组成。Q次询问,现在从中选取3个点a,b,c。 以一个点为顶点,另外两个点为起始点走最短路。要求得3种组合中,公共点数量最多的情况。


思路:枚举3种情况。

节点A,B之间最短路距离是:dis(A,B)=dep[A]-dep[LCA(A,B)]+dep[B]-dep[LCA(A,B)];

两节点A,B到节点C的    公共点个数=  (  dis(A,C)+dis(B,C)-dis(A,B)  )/2  + 1

接下来主要是模板一套就好了


数据分析:2 ≤ n ≤ 1051 ≤ q ≤ 105


复杂度分析:O(nlogn + q * logn)


CODE:(详见 算法学习之   LCA模板)传送门

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=1e5+50;const int maxlog=20;int n,q,root=1;int par[maxlog][maxn];int dep[maxn];vector <int> G[maxn];void dfs(int v,int p,int d){    par[0][v]=p;    dep[v]=d;    for(int i=0;i<G[v].size();i++)        if(G[v][i]!=p)  dfs(G[v][i],v,d+1);    return ;}void init(){    dfs(root,-1,0);    for(int k=0;k<=maxlog-2;k++)        for(int v=1;v<=n;v++)            par[k+1][v]= par[k][v]<0 ? -1:par[k][par[k][v]];    return ;}int lca(int u,int v){    if(dep[u]>dep[v])   swap(u,v);    for(int k=0;k<maxlog;k++)        if((dep[v]-dep[u])>>k & 1)            v=par[k][v];    if(u==v)    return u;    for(int k=maxlog-1;k>=0;k--)        if(par[k][u]!=par[k][v])    u=par[k][u],v=par[k][v];    return par[0][u];}int dis(int u,int v){return dep[u]+dep[v]-dep[lca(u,v)]*2;}int cul(int t, int s ,int f){return (  dis(s,f)+dis(t,f)-dis(s,t)  )/2;}int main(void){    cin >> n >> q;    for(int i=2;i<=n;i++)    {        int t;        scanf("%d",&t);        G[i].push_back(t);        G[t].push_back(i);    }    init();    while(q--)    {        int a,b,c;        scanf("%d%d%d",&a,&b,&c);        printf("%d\n",max(  cul(a,b,c),max(cul(a,c,b) , cul(b,c,a)) )+1  );    }    return 0;}


阅读全文
0 0