NC13950 Alliances(LCA)

对于每个帮派求他们的lca,对于每个询问,先将所含的所有帮派求lca,将这个和当前首都比较,如果首都不在最高点的lca的子树当中,那么他的答案就是这个最高点lca和首都的距离

如果在这个子树下,那么只需要求取dfs序在首都前后的两个点求一个min即可。

分析这道题目,我们想到lca的原因是,这里有树上两点的距离的判定,这种题,很多情况下都是lca来做,但是因为题目中有很多点,因此我们要缩减计算的次数。通过思考,我们发现对于可以分成两种情况讨论。而对于子树中的情况,其实不难想到dfs序+二分查找,因为前后总是最近的,其他的点没有意义。有个点是因为两个城市之间的所有城市都是特殊点,因此,求得前后点后,还要进一步转化。这个转化比较明显,可以通过观察获得。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+10;
const int mod=1e9+7;
int h[N],ne[N],e[N],idx;
int dfn[N],times;
int f[N][35];
int depth[N];
vector<int> num[N];
int p[N];
int id[N];
int sz[N];
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa){
    depth[u]=depth[fa]+1;
    f[u][0]=fa;
    dfn[u]=++times;
    id[times]=u;
    int i;
    for(i=1;i<=30;i++){
        f[u][i]=f[f[u][i-1]][i-1];
    }
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa)
            continue;
        dfs(j,u);
    }
}
int lca(int a,int b){
    if(depth[a]<depth[b])
        swap(a,b);
    int i;
    for(i=30;i>=0;i--){
        if(depth[f[a][i]]>=depth[b]){
            a=f[a][i];
        }
    }
    if(a==b)
        return a;
    for(i=30;i>=0;i--){
        if(f[a][i]!=f[b][i]){
            a=f[a][i];
            b=f[b][i];
        }
    }
    return f[a][0];
}
int cal(int a,int b){
    return depth[a]+depth[b]-2*depth[lca(a,b)];
}
int main(){
    ios::sync_with_stdio(false);
    int n;
    cin>>n;
    int i;
    memset(h,-1,sizeof h);
    for(i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dfs(1,0);
    int k;
    cin>>k;
    for(i=1;i<=k;i++){
        int x;
        cin>>x;
        int now;
        for(int j=1;j<=x;j++){
            int y;
            cin>>y;
            num[i].push_back(dfn[y]);
            if(j==1){
                now=y;
            }
            else{
                now=lca(now,y);
            }
        }
        p[i]=now;
        sort(num[i].begin(),num[i].end());
    }
    int q;
    cin>>q;
    while(q--){
        int v,c;
        cin>>v>>c;
        int now;
        for(i=1;i<=c;i++){
            cin>>sz[i];
            if(i==1){
                now=p[sz[i]];
            }
            else{
                now=lca(now,p[sz[i]]);
            }
        }
        if(lca(now,v)!=now){
            cout<<-2*depth[lca(now,v)]+depth[v]+depth[now]<<endl;
            continue;
        }
        int ans=0x3f3f3f3f;
        for(i=1;i<=c;i++){
            int pos=lower_bound(num[sz[i]].begin(),num[sz[i]].end(),dfn[v])-num[sz[i]].begin();
            if(pos!=(int)num[sz[i]].size()){
                int tmp=lca(v,id[num[sz[i]][pos]]);
                ans=min(ans,cal(tmp,v));
            }
            pos=lower_bound(num[sz[i]].begin(),num[sz[i]].end(),dfn[v])-num[sz[i]].begin()-1;
            if(pos!=-1){
                int tmp=lca(v,id[num[sz[i]][pos]]);
                ans=min(ans,cal(tmp,v));
            }
        }
        cout<<ans<<endl;
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13966484.html