您的位置:首页 > 其它

hdu 4409 Family Name List LCA +stl

2012-09-22 18:12 357 查看
http://acm.hdu.edu.cn/showproblem.php?pid=4409

赛后才过只能说悲剧了,知道思路,stl不熟悉,所以导致写的很慢....占据了很多时间,手速+代码准确度。。哎。。。

题意:

给你一个家谱,n个人的姓名,姓名前边的点代表了他是第几代人。每个人的祖先肯定在他之前出现。有三种操作:

L:输出这个家族的序列,不是按层数,而是递归的输出,还要保证字典序升序;

b name 输出name的兄弟个数,注意这里堂兄弟不算:

c name1 name2 求name1 name2的最近公共祖先。

思路:

首先我用set建图这样就能保证L输出时按字典序输出,mp用来进行映射,rmq+lca求最近公共祖先,这里注意的是如果x,y的lca等于x或者y就要输出lca的父亲才是他们的LCA。还有如果访问Mr.X的兄弟的话要输出1.

View Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <string>

#define CL(a,num) memset((a),(num),sizeof(a))
#define iabs(x)  ((x) > 0 ? (x) : -(x))

#define Max(a , b) ((a) > (b) ? (a) : (b))

#define ll __int64
#define inf 0x7f7f7f7f
#define MOD 100000007
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
#define pi acos(-1.0)
#define test puts("<------------------->")
#define maxn 100007
#define M 100007
#define N 30007
using namespace std;
//freopen("din.txt","r",stdin);

map<string,int>mp;
set<string>st
;

int pos
;//点为i的编号
int bro
;//记录i的兄弟数

int E[N << 1],D[N << 1],R
,dp[N << 1][30];//rmq+lca

char strT
[66];
int pow2[32],pa
;//记录i点的父节点
int n,top;

void dfs(int u,int h){

E[++top] = u;
D[top] = h;
R[u] = top;
set<string>::iterator it;
for(it = st[u].begin(); it != st[u].end(); ++it){
int v = mp[*it];
dfs(v , h+1);
E[++top] = u;
D[top] = h;
}
return;
}
int Min(int i,int j){
if (D[i] < D[j]) return i;
else return j;
}

//rmq的初始化
void init_rmq()
{
for (int i = 0; i < 30; ++i) pow2[i] = 1<<i;
for(int i = 1;i <= top; ++i){
dp[i][0] = i;
}
for(int j = 1; pow2[j] <= top; ++j){
for(int i = 1; (i + pow2[j] - 1) <= top; ++i){
dp[i][j] = Min(dp[i][j-1],dp[i + (1 << (j-1))][j-1]);
}

}
return;
}

int rmq(int l,int r){
int d = log((double)(r - l + 1)) / log(2.0);
return Min(dp[l][d],dp[r - pow2[d] + 1][d]);
}
//L顺序输出,这里set直接排序了
void dfspath(int u){
set<string>::iterator it;
for (it = st[u].begin(); it != st[u].end(); it++){
int v = mp[*it];
printf("%s\n",strT[v]);
dfspath(v);
}
}
int main(){

// freopen("din.txt","r",stdin);
int i,j;
while (~scanf("%d",&n)){
if (!n) break;

CL(pos,0); mp.clear();
for (i = 0; i <= n; ++i) st[i].clear();

for (i = 0; i < n; ++i){
scanf("%s",strT[i]);
//找点的个数
int tmpnum = 0;
int sz = strlen(strT[i]);
for (j = 0; j < sz; ++j){
if (strT[i][j] == '.') tmpnum++;
else break;
}
//点为tmpnum的编号
pos[tmpnum] = i;

string s;
for (; j < sz; ++j){
s.push_back(strT[i][j]);
}
//cout<<strT[i]<<"*********"<<s<<endl;
mp[s] = i;//建立映射关系
if (tmpnum != 0){
st[pos[tmpnum - 1]].insert(s);
pa[i] = pos[tmpnum - 1];//记录该节点的父亲节点
}
}

CL(bro,0);
set<string>::iterator it;
for (i = 0; i < n; ++i){
//printf("%d %s>>\n",i,strT[i]);
int sz = st[i].size();
for (it = st[i].begin(); it != st[i].end(); ++it){
int tmp = mp[*it];
//cout<<tmp<<endl;
bro[tmp] = sz;//统计兄弟数量
}
}
bro[0] = 1;//这里很容易错,注意要初始化
//for (i = 1; i < n; ++i) printf(">>%d %d\n",i,bro[i]);

//lca+rmq的过程
top = 0;
dfs(0,0);
init_rmq();

char op[3];
int q;
scanf("%d",&q);
while (q--){
scanf("%s",op);
string tmps;
if (op[0] == 'L'){
printf("%s\n",strT[0]);
dfspath(0);
}
else if (op[0] == 'b'){
cin>>tmps;
int posn = mp[tmps];
printf("%d\n",bro[posn]);
}
else{
string s1,s2;
int lca;
cin>>s1>>s2;

int x = mp[s1];
int y = mp[s2];

if (R[x] <= R[y]) lca = E[rmq(R[x],R[y])];
else lca = E[rmq(R[y],R[x])];
if (lca == x || lca == y) lca = pa[lca];//注意这里的处理
int t;
int L = strlen(strT[lca]);
for (t = 0; t < L; ++t){
if (strT[lca][t] != '.') printf("%c",strT[lca][t]);
}
printf("\n");
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: