首页 > 代码库 > HDU 4409 Family Name List --乱搞、LCA

HDU 4409 Family Name List --乱搞、LCA

题意: 给出一些名字,名字间有父子关系,有三种操作:

1.按祖先到后代,兄弟间按字典序由小到大排序,然后输出

2.求某个节点的兄弟节点有多少个,包括自己(注意,根节点的兄弟节点是1)

3.求节点a和b的公共祖先 (注意:如果公共祖先是a或b,必须要输出其父亲,与传统的LCA可以是自己不同)

解法: 先把整棵树整理出来,son[u]表示u的儿子个数,用来求兄弟个数, fa[u]表示父亲,Gson存储儿子的标号,关于排序的问题,先读入所有名字,然后排个序哈希一下,使字典序小的节点标号一定小,那么直接sort(Gson.begin(),Gson.end()) 就将儿子排序了。

然后用RMQ 搞在线LCA 即可

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cstdlib>#include <cmath>#include <algorithm>#include <string>#include <vector>#include <map>using namespace std;#define N 30107map<string,int> mp;int son[N],fa[N],cnt[N];vector<int> Gson[N];string TS[N],NS[N];int ati[60004],f[60006],bn,b[90008],dp[60005][32],ind;void dfs(int u,int dep){    for(int i=0;i<dep;i++) printf(".");    cout<<NS[u]<<endl;    for(int i=0;i<Gson[u].size();i++)    {        int v = Gson[u][i];        dfs(v,dep+1);    }}void init(){    memset(ati,0,sizeof(ati));    memset(f,0,sizeof(f));    memset(b,0,sizeof(b));    memset(dp,0,sizeof(dp));    bn = ind = 0;}void dfs_2(int u,int father){    int tmp = ++ind;    f[tmp] = u;    b[++bn] = tmp;    ati[u] = bn;    for(int i=0;i<Gson[u].size();i++)    {        int v = Gson[u][i];        if(v==father) continue;        dfs_2(v,u);        b[++bn]=tmp;    }}void RMQ_init(int n){    for (int i=1; i<=n; i++)  dp[i][0]=b[i];    int m=floor(log((double)n*1.0)/log((double)2.0));    for (int j=1; j<=m; j++)      for (int i=1; i<=n-(1<<j)+1; i++)          dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);}int RMQ(int l,int r){    int k=floor(log((double)r-l+1)/log(2.0));    return min(dp[l][k],dp[r-(1<<k)+1][k]);}int LCA(int a,int b){    if (ati[a] > ati[b]) swap(a,b);    return f[RMQ(ati[a],ati[b])];}int main(){    int n,m,i,j;    while(scanf("%d",&n)!=EOF && n)    {        mp.clear();        memset(son,0,sizeof(son));        memset(fa,0,sizeof(fa));        string ss;        for(i=0;i<=n;i++) Gson[i].clear();        for(i=1;i<=n;i++)        {            cin>>TS[i];            int len = TS[i].length();            for(j=0;j<len;j++)                if(TS[i][j] != .) break;            NS[i] = TS[i].substr(j,len-j);        }        sort(NS+1,NS+n+1);        for(i=1;i<=n;i++)            mp[NS[i]] = i;        for(i=1;i<=n;i++)        {            ss = TS[i];            int len = ss.length();            for(j=0;j<len;j++)                if(ss[j] != .) break;            string S = ss.substr(j,len-j);            cnt[j] = mp[S];             if(j != 0)            {                fa[mp[S]] = cnt[j-1];  //最近的有j-1个‘.‘的名字就是有j个‘.‘的名字的父亲                son[cnt[j-1]]++;                Gson[cnt[j-1]].push_back(mp[S]);            }            else                fa[mp[S]] = 0;        }        for(i=1;i<=n;i++)            sort(Gson[i].begin(),Gson[i].end());        for(i=1;i<=n;i++)            if(fa[i] == 0) break;        int father = i;        init();        dfs_2(father,0);        RMQ_init(bn);        scanf("%d",&m);        char s[5];        while(m--)        {            scanf("%s",s);            if(s[0] == L)                dfs(father,0);            else if(s[0] == b)            {                cin>>ss;                int k = mp[ss];                if(k == father) puts("1");                else printf("%d\n",son[fa[k]]);            }            else            {                string S1,S2;                cin>>S1>>S2;                int ms1 = mp[S1];                int ms2 = mp[S2];                int fat = LCA(ms1,ms2);                if(fat == ms1 || fat == ms2)  cout<<NS[fa[fat]]<<endl;                else                          cout<<NS[fat]<<endl;            }        }    }    return 0;}
View Code

 

HDU 4409 Family Name List --乱搞、LCA