hihocoder 1387 A Research on The Hundred Family Surnames

題解網址

以下爲搬運

題意: 給一棵樹,每個節點上有個顏色,很多詢問,詢問兩種顏色,問從這兩種顏色中各取一個節點,距離最大是多少。

題解:處理出每種顏色的節點們的直徑(也就是距離最大的點對)。然後對於兩種詢問顏色(a,b) 的直徑(au,av)(bu,bv) ,答案就是max{dis(au,bu),dis(au,bv),dis(av,bu),dis(av,bv)}

O(nlogn) 算一種顏色的節點們的直徑的方法:增量添加節點同時維護直徑,假設新加的節點是z ,原直徑是(x,y) ,那麼新直徑是(x,y),(x,z),(y,z) 中的一個。


以下爲代碼

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

const int maxn = 112345, ROOT = 1;
vector<int> edge[maxn];

int fa[maxn],son[maxn],siz[maxn];
int deep[maxn],top[maxn],tid[maxn];
int _cnt;

void dffs(int st,int Fa,int Deep){
    siz[st] = 1,deep[st] = Deep;
    fa[st] = Fa,son[st] = -1;
    for(auto &x:edge[st]){
        if(x != Fa){
            dffs(x,st,Deep+1);
            siz[st] += siz[x];
            if(son[st] == -1 || siz[son[st]] < siz[x])
                son[st] = x;
        }
    }
}
void dfss(int st,int Top){
    top[st] = Top,tid[st] = _cnt++;
    if(son[st] != -1)
        dfss(son[st],Top);
    for(auto &x:edge[st]){
        if(son[st] != x && fa[st] != x){
            dfss(x,x);
        }
    }
}
void splite(){
    _cnt = 1;
    dffs(ROOT,-1,1);
    dfss(ROOT,ROOT);
}

int Lca(int x,int y){
    int tx = top[x],ty = top[y];
    while(tx != ty){
        if(deep[tx] < deep[ty])
            swap(tx,ty),swap(x,y);
        x = fa[tx],tx = top[x];
    }
    if(deep[x] < deep[y])
        swap(x,y);
    return y;
}
int dis(int x,int y){
    int lca = Lca(x,y);
    return deep[x] + deep[y] - 2 * deep[lca] + 1;
}

char name[maxn][8];
map<string,pair<int,int> >M;

void dfs(int st,int fa){
    if(M.find(name[st]) == M.end())
        M[name[st]] = make_pair(st,st); 
    else{
        auto & var = M[name[st]];
        int va = var.first,vb = var.second;
        if(dis(va,st) < dis(vb,st))
            swap(va,vb);
        if(dis(va,vb) < dis(va,st))
            var = make_pair(va,st);
    }
    for(auto x : edge[st]){
        if(x == fa) continue;
        dfs(x,st);
    }
}

int query(string x,string y){
    if(M.find(x) == M.end()) return -1;
    if(M.find(y) == M.end()) return -1;
    auto a = M[x], b = M[y];
    return max(max(dis(a.first,b.first),dis(a.first,b.second)),
               max(dis(a.second,b.first),dis(a.second,b.second)));
}
char inp[2][10];

int main(){
    int n,m;
    while(~scanf("%d %d",&n,&m)){
        for(int i=1;i<=n;i++){
            scanf("%s",name[i]);
            edge[i].clear();
        }
        int x,y;
        for(int i=1;i<n;i++){
            scanf("%d %d",&x,&y);
            edge[x].push_back(y);
            edge[y].push_back(x);
        }
        splite();
        M.clear();
        dfs(1,0);
        while(m--){
            scanf("%s %s",inp[0],inp[1]);
            printf("%d\n",query(inp[0],inp[1]));
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章