hdu 4409 Family Name List(LCA&有坑点)

Family Name List

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 882    Accepted Submission(s): 271

Problem Description

Kong belongs to a huge family. Recently he got a family name list which lists all men (no women) in his family over many generations.

The list shows that the whole family has a common ancestor, let‘s call him Mr. X. Of course, everybody except Mr.X in the list is Mr. X‘s descendant. Everybody‘s father is shown in the list except that Mr. X‘s father is not recorded. We define that Mr. X‘s
generation number is 0. His son‘s generation number is 1.His grandson‘s generation number is 2, and so on. In a word, everybody‘s generation number is 1 smaller than his son‘s generation number. Everybody‘s generation number is marked in some way in the list.

Now Kong is willing to pay a lot of money for a program which can re-arrange the list as he requires ,and answer his questions such as how many brothers does a certain man have, etc. Please write this program for him.

Input

There are no more than 15 test cases.

For each test case:

The first line is an integer N( 1 <= N <= 30,000), indicating the number of names in the list.

The second line is the name of Mr. X.

In the next N-1 lines, there is a man‘s name in each line. And if the man‘s generation number is K, there are K dots( ‘.‘) before his name.

Please note that :

1) A name consists of only letters or digits( ‘0‘-‘9‘).

2) All names are unique.

3) Every line‘s length is no more than 60 characters.

4) In the list, a man M‘s father is the closest one above M whose generation number is 1 less than M.

5) For any 2 adjacent lines in the list, if the above line‘s generation number is G1 and the lower line‘ s generation number is G2, than G2 <= G1 +1 is guaranteed.

After the name list, a line containing an integer Q(1<=Q<=30,000) follows, meaning that there are Q queries or operations below.

In the Next Q lines, each line indicates a query or operation. It can be in the following 3 formats:

1) L

Print the family list in the same format as the input, but in a sorted way. The sorted way means that: if A and B are brothers(cousins don’t count), and A‘s name is alphabetically smaller than B‘s name, then A must appear earlier than B.

2) b name

Print out how many brothers does "name" have, including "name" himself.

3) c name1 name2

Print out the closest common ancestor of "name1" and "name2". "Closest" means the generation number is the largest. Since Mr. X has no ancestor in the list, so it‘s guaranteed that there is no question asking about Mr. X‘s ancestor.

The input ends with N = 0.

Output

Already mentioned in the input.

Sample Input

9
Kongs
.son1
..son1son2
..son1son1
...sonkson2son1
...son1son2son2
..son1son3
...son1son3son1
.son0
7
L
b son1son3son1
b son1son2
b sonkson2son1
b son1
c sonkson2son1 son1son2son2
c son1son3son1 son1son2
0 

Sample Output

Kongs
.son0
.son1
..son1son1
...son1son2son2
...sonkson2son1
..son1son2
..son1son3
...son1son3son1
1
3
2
2
son1son1
son1

Source

2012 ACM/ICPC Asia Regional Jinhua Online

Recommend

zhoujiaqi2010   |   We have carefully selected several similar problems for you:  5053 5052 5051 5050 5049

题意:

给你一棵树。

有三种操作。

1.输出树的dfs序。

字典序小的先输出。

2.输出一个结点的父亲有多少儿子。包含自己。

3.输出u,v的LCA。

思路:

这题输入比較蛋疼。我是用一个栈来建树的。

不知道有其他什么高级方法没。

然后对于操作1.因为要字典序小的的先dfs。那么仅仅好用 不是非常熟悉的vector存边了。然后对边按名字字典序排序。

然后dfs一次把答案存起来。对于2记录下一个结点的父亲是谁即可了。

对于3.tarjan离线处理。这题有个坑点就是LCA不能是自己。over。

具体见代码:

#include<cstdio>
#include<vector>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
#include<map>
using namespace std;
const int maxn=30010;
int cnt,ptr,pp,vis[maxn],ty[maxn],aans[maxn];
int st[maxn],rk[maxn],fa[maxn],pa[maxn],uu[maxn],vv[maxn];
char na[100];
vector<int> G[maxn];
string name[maxn],ans[maxn];
map<string,int> mp;
struct node
{
    int v,id;
    node *next;
} ed[maxn<<1],*head[maxn];
void adde(int u,int v,int id)
{
    ed[ptr].v=v;
    ed[ptr].id=id;
    ed[ptr].next=head[u];
    head[u]=&ed[ptr++];
}
bool cmp(int a,int b)
{
    return name[a]<name[b];
}
void dfs(int u)
{
    string op=".";
    ans[pp]="";
    for(int i=0;i<rk[u];i++)
        ans[pp]+=op;
    ans[pp++]+=name[u];
    for(int i=0;i<G[u].size();i++)
    {
        pa[G[u][i]]=u;
        dfs(G[u][i]);
    }
}
int getfa(int x)
{
    if(fa[x]==x)
        return x;
    return fa[x]=getfa(fa[x]);
}
void tarjan(int u)
{
    vis[u]=1,fa[u]=u;
    for(node *p=head[u];p!=NULL;p=p->next)
    {
        if(vis[p->v])
            aans[p->id]=getfa(p->v);
    }
    for(int i=0;i<G[u].size();i++)
    {
        tarjan(G[u][i]);
        fa[G[u][i]]=u;
    }
}
int main()
{
    int i,j,n,m,tp,ct,id,u,v;
    string aa,bb;
    char cmd[20];

    while(scanf("%d",&n),n)
    {
        for(i=0;i<=n;i++)
            G[i].clear();
        mp.clear();
        tp=cnt=1;
        st[0]=0,rk[0]=-1;
        for(i=0;i<n;i++)
        {
            scanf("%s",na);
            ct=0;
            for(j=0;na[j];j++)
                if(na[j]==‘.‘)
                    ct++;
                else
                    break;
            string nna(na+ct);
            //cout<<nna<<endl;
            if(!mp.count(nna))
            {
                name[cnt]=nna;
                rk[cnt]=ct;
                mp[nna]=cnt++;
            }
            id=mp[nna];
            while(rk[st[tp-1]]>=rk[id])
                tp--;
            G[st[tp-1]].push_back(id);
            st[tp++]=id;
        }
        for(i=1;i<=n;i++)
            sort(G[i].begin(),G[i].end(),cmp);
        pp=0;
        dfs(1);
        ptr=0;
        memset(head,0,sizeof head);
        memset(vis,0,sizeof vis);
        scanf("%d",&m);
        for(i=0;i<m;i++)
        {
            scanf("%s",cmd);
            if(cmd[0]==‘L‘)
                ty[i]=0;
            else if(cmd[0]==‘b‘)
            {
                ty[i]=1;
                cin>>aa;
                id=mp[aa];
                aans[i]=G[pa[id]].size();
            }
            else
            {
                ty[i]=2;
                cin>>aa>>bb;
                u=mp[aa],v=mp[bb];
                uu[i]=u,vv[i]=v;
                adde(u,v,i);
                adde(v,u,i);
            }
        }
        tarjan(1);
        for(i=0;i<m;i++)
        {
            if(ty[i]==0)
            {
                for(j=0;j<n;j++)
                    cout<<ans[j]<<endl;
            }
            else if(ty[i]==1)
                printf("%d\n",aans[i]);
            else
            {
                if(aans[i]==uu[i]||aans[i]==vv[i])
                    aans[i]=pa[aans[i]];
                cout<<name[aans[i]]<<endl;
            }
        }
    }
    return 0;
}
时间: 2024-10-27 11:30:56

hdu 4409 Family Name List(LCA&amp;有坑点)的相关文章

hdu 4409 Family Name List(LCA&amp;有坑点)

Family Name List Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 882    Accepted Submission(s): 271 Problem Description Kong belongs to a huge family. Recently he got a family name list which l

HDU 4008 Parent and son LCA+树形dp

题意: 给定case数 给定n个点的树,m个询问 下面n-1行给出树边 m个询问 x y 问:以x为根,y子树下 y的最小点标的儿子节点 和子孙节点 思路: 用son[u][0] 表示u的最小儿子 son[u][2] 表示u的次小儿子 son[u][1] 表示u的最小子孙 若lca(x,y)  !=y  则就是上述的答案 若lca(x,y) == y 1.y != 1 那么最小儿子就是除了x外的节点,且此时father[y] 也是y的儿子节点, 而最小的子孙节点就是1 2.y==1 那么特殊处理

hdu 4929 Another Letter Tree(LCA+DP)

hdu 4929 Another Letter Tree(LCA+DP) 题意:有一棵树n个节点(n<=50000),树上每个节点上有一个字母.m个询问(m<=50000),每次询问一个(a,b),问a节点到b节点的点不重复路径组成的字符串中子序列为s0的情况有多少种,s0长度小于等于30(注意s0是已经给定的,而不是每次询问都会给出一个新的). 解法:一个很直观的想法,求出lca(设其为w)后,枚举x,求出a到w的路径上,能匹配s0的x长度前缀的情况有多少种,令其为c[x].再求出b到w的路

hdu 1202The calculation of GPA (简单题+坑)

The calculation of GPA Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 18748    Accepted Submission(s): 4331 Problem Description 每学期的期末,大家都会忙于计算自己的平均成绩,这个成绩对于评奖学金是直接有关的.国外大学都是计算GPA(grade point a

HDU 4409 Family Name List --乱搞、LCA

题意: 给出一些名字,名字间有父子关系,有三种操作: 1.按祖先到后代,兄弟间按字典序由小到大排序,然后输出 2.求某个节点的兄弟节点有多少个,包括自己(注意,根节点的兄弟节点是1) 3.求节点a和b的公共祖先 (注意:如果公共祖先是a或b,必须要输出其父亲,与传统的LCA可以是自己不同) 解法: 先把整棵树整理出来,son[u]表示u的儿子个数,用来求兄弟个数, fa[u]表示父亲,Gson存储儿子的标号,关于排序的问题,先读入所有名字,然后排个序哈希一下,使字典序小的节点标号一定小,那么直接

HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点对,然后判断最少有多少个坏点. 题解 :求每个点对的LCA,然后根据LCA的深度排序.从LCA最深的点对开始,如果a或者b点已经有点被标记了,那么continue,否者标记(a,b)LCA的子树每个顶点加1. #include<Bits/stdc++.h> using namespace std;

HDU 3078:Network(LCA之tarjan)

http://acm.hdu.edu.cn/showproblem.php?pid=3078 题意:给出n个点n-1条边m个询问,每个点有个权值,询问中有k,u,v,当k = 0的情况是将u的权值修改成v,当k不为0的情况是问u和v的路径中权值第k大的点的权值是多少. 思路:比较暴力的方法,可能数据太水勉强混过去了.对于每一个询问的时候保留两个点之间的lca,还有计算出两个点之间的点的个数(询问的时候如果点的个数小于k就不用算了),然后tarjan算完之后对每个询问再暴力路径上的每个点放进vec

HDU 2460 Network(桥+LCA)

http://acm.hdu.edu.cn/showproblem.php?pid=2460 题意:给出图,求每次增加一条边后图中桥的数量. 思路: 先用tarjan算法找出图中所有的桥,如果lowv>pre[u],那么u—v就是桥,此时可以标记一下v. 之后就是利用LCA,找到两个节点的公共祖先,在这条路径上的桥就不再是桥了.(此时就相当于这些桥组成的树,可以在脑海中缩点) 1 #include<iostream> 2 #include<algorithm> 3 #incl

[HDU]P2586 How far away?[LCA]

[HDU]P2586 How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18675    Accepted Submission(s): 7274 Problem Description There are n houses in the village and some bidirectional road