您的位置:首页 > 其它

HDU 4409 Family Name List(LCA)

2012-10-05 20:25 465 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4409

题意:给定一个家谱。有三种询问:

(1)L重新打印家谱,同一代的人按照升序;

(2)b name 输出name的亲兄弟有多少个?

(3)c name1 name2输出name1和name2 的最近公共祖先。

注意(3):如果最近公共祖先是name1或者name2,那么要输出其父亲。(因为自己不能是自己的祖先。。)

思路:建图的时候就按照正常的建,但是输出的时候将同一个父亲的孩子排序输出(2)在DFS的时候顺便统计一下;(3)就是LCA。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

const int MAX=30005;  //节点数量
struct node
{
int v,next;
};

struct Node
{
char s[65];
int id;
};

int cmp(Node a,Node b)
{
return strcmp(a.s,b.s)<0;
}

node edges[MAX<<1];
int head[MAX],e;
int pre[MAX],dep[MAX];
int id[MAX]; //节点第一次被遍历的顺序
int RMQ[MAX*3][20];
int curID;
//F[i]表示第i个遍历的节点
//B[i]表示F[i]在树中的深度
int F[MAX*3],B[MAX*3];

int father[MAX],d[MAX];
int ID;
Node hash[MAX],hash1[MAX];

int add(char str[])
{
ID++;
strcpy(hash[ID].s,str);
hash[ID].id=ID;
return ID;
}

int getID(char str[])
{
int low=1,high=ID,mid;
while(low<=high)
{
mid=(low+high)>>1;
if(strcmp(hash[mid].s,str)==0) break;
if(strcmp(hash[mid].s,str)<0) low=mid+1;
else high=mid-1;
}
return hash[mid].id;
}

void init()
{
curID=0;
ID=0;
memset(head,-1,sizeof(head));
e=0;
}

void Add(int u,int v)
{
edges[e].v=v;
edges[e].next=head[u];
head[u]=e++;
}

int sonNum[MAX];

void DFS(int u,int p,int Dep)
{
int i,v;

curID++;
F[curID]=u;  B[curID]=Dep;
id[u]=curID; pre[u]=p; dep[u]=Dep;

sonNum[u]=0;
for(i=head[u];i!=-1;i=edges[i].next)
{
v=edges[i].v;
if(v==p) continue;
DFS(v,u,Dep+1);
curID++;
F[curID]=u;
B[curID]=Dep;
sonNum[u]++;
}
}

void initRMQ()
{
int i,j,x,y;
for(i=1;i<=curID;i++) RMQ[i][0]=i;
for(j=1;(1<<j)<=curID;j++) for(i=1;i+(1<<j)-1<=curID;i++)
{
x=RMQ[i][j-1];
y=RMQ[i+(1<<(j-1))][j-1];
RMQ[i][j]=B[x]<B[y]?x:y;
}
}

int getLCA(int a,int b)
{
int k,x,y;
a=id[a];b=id[b];
if(a>b) k=a,a=b,b=k;
k=log(1.0+b-a)/log(2.0);
x=RMQ[a][k];
y=RMQ[b-(1<<k)+1][k];
return B[x]<B[y]?F[x]:F[y];
}

void build(int n)
{
char str[65];
int i,j,k,u,v;

scanf("%s",str);
u=add(str);
d[u]=0;father[u]=-1;
for(i=2;i<=n;i++)
{
scanf("%s",str);
for(j=0;str[j]=='.';j++);
for(k=j;str[k];k++) str[k-j]=str[k];
str[k-j]='\0';
v=add(str);
d[v]=j;
while(d[u]+1!=d[v]) u=father[u];
Add(u,v);
father[v]=u;
u=v;
}
}

int temp[MAX],start[MAX],size[MAX];
void print(int u,int dep)
{
int i,j,v;
for(i=1;i<=dep;i++) putchar('.');
printf("%s\n",hash1[u].s);
for(i=start[u];i<start[u]+size[u];i++)
{
j=temp[i];
v=edges[j].v;
print(v,dep+1);
}
}

int cmp1(int a,int b)
{
int v1=edges[a].v;
int v2=edges[b].v;
return strcmp(hash1[v1].s,hash1[v2].s)<0;
}

void deal(int Q)
{
char cmd[5],str[65],str1[65];
int i,j,u,v;
for(i=1;i<=ID;i++) hash1[i]=hash[i];
sort(hash+1,hash+ID+1,cmp);
u=1;
for(i=1;i<=ID;i++)
{
size[i]=0;
start[i]=u;
for(j=head[i];j!=-1;j=edges[j].next)
{
temp[u]=j;
size[i]++;
u++;
}
if(size[i])
{
sort(temp+start[i],temp+start[i]+size[i],cmp1);
}
}
while(Q--)
{
scanf("%s",cmd);
if(cmd[0]=='L')
{
print(1,0);
}
else if(cmd[0]=='b')
{
scanf("%s",str);
u=getID(str);
if(father[u]==-1) puts("1");
else printf("%d\n",sonNum[father[u]]);
}
else if(cmd[0]=='c')
{
scanf("%s%s",str,str1);
u=getID(str);
v=getID(str1);
i=getLCA(u,v);
if(i==u||i==v) i=father[i];
printf("%s\n",hash1[i].s);
}
}
}

int n,Q;

int main()
{
while(scanf("%d",&n),n)
{
init();
build(n);
DFS(1,0,0);
initRMQ();
scanf("%d",&Q);
deal(Q);
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: