您的位置:首页 > 其它

HDU 4409 Family Name List --乱搞、LCA

2014-11-09 22:38 295 查看
题意: 给出一些名字,名字间有父子关系,有三种操作:

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 30107

map<string,int> mp;
int son
,fa
,cnt
;
vector<int> Gson
;
string TS
,NS
;
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: