天梯賽 冰島人(LCA)

思路:按照長輩的名是孩子的姓這個關係建樹,建完樹以後求LCA,但是細節居多。坑點巨多TT

代碼如下:

/* 
坑點: 
存在孩子以女的長輩名作爲後綴,這種情況孩子跟長輩其實沒有關係,wa第三個點
兒子有可能出現在父親前面,wa最後一個點  
3
scj sm
xx scjsdottir
xxx xxsson
10
xx scj xxx xx(應該yes) 
*/
#include<iostream>
#include<cstdio>
#include<stack>
#include<cstring>
#include<map>
#include<queue>
#define maxn 100010
using namespace std;
map<string,int> ID;//每個名映射成一個整數
int sex[maxn];//每個人的性別 
queue<int > F;//祖先節點們
map<int,vector<int> > C;//每個姓氏下的人 
int pre[maxn];//每個人的父節點
int f[maxn];//並查集 
int fa[maxn][30];//每個人的第2^j個祖先
int dep[maxn];//每個點的深度,根節點爲1 
int n; 
int lg[maxn];
void build()
{
	while(!F.empty())
	{
		int now=F.front();F.pop();
		//cout<<now<<" "<<dep[now]<<" "<<f[now]<<endl;
		vector<int> &v=C[now];
		for(int i=0;i<v.size();i++)
		{
			f[v[i]]=f[now];
			dep[v[i]]=dep[now]+1;
			fa[v[i]][0]=now;
			//G[now].push_back(v[i]);
			F.push(v[i]);
		}
	}
}
void init()
{
	build();
	for(int j=0;j<20;j++)
	{
		for(int i=1;i<=n;i++)
		{
			//cout<<i<<"走"<<j<<"->"<<fa[i][j]<<endl;
			if(fa[i][j]<0) fa[i][j+1]=-1;
			else fa[i][j+1]=fa[fa[i][j]][j];
			
		}
	}
}
int LCA(int u,int v)
{
    if(dep[u]>dep[v]) swap(u,v);
    int temp=dep[v]-dep[u];
    for(int i=0;(1<<i)<=temp;i++)      //使u,v在同一深度
    {
        if((1<<i)&temp)
            v=fa[v][i];
    }
    if(v==u) return u;
    for(int i=19;i>=0;i--)  //兩個節點一起往上走
    {
        if(fa[u][i]!=fa[v][i])
        {
            u=fa[u][i];
            v=fa[v][i];
            //cout<<u<<" "<<v<<endl;
        }
    }
    return fa[u][0];
}
int main(){
	//freopen("data.out","w",stdout);
	ios::sync_with_stdio(false); 
	cin>>n;
	string xing,ming;
	string ff[maxn];
	for(int i=1;i<=n;i++)
	{
		cin>>ming>>xing;
		int len=xing.length();
		ID[ming]=i;
		f[i]=i;
		if(xing[len-1]=='m'){
            sex[i]=1;
        }else if(xing[len-1]=='f'){
            sex[i]=0;
        }else if(xing[len-1]=='n'){
            sex[i]=1;
        }else if(xing[len-1]=='r'){
            sex[i]=0;
        }
        if(xing[len-1]=='m'||xing[len-1]=='f')
		{
			fa[i][0]=-1;dep[i]=1;f[i]=i;
			F.push(i);//祖先 
			continue;
		}
		ff[i]=xing;
	}
	for(int i=1;i<=n;i++)
	{
		if(dep[i]==1) continue;
		int len=ff[i].length();
		if(ff[i][len-1]=='n')
		{
			ff[i].erase(len-4,4);
			int v=ID[ff[i]];
			if(sex[v]==1)//男父親 
			{
				C[v].push_back(i);
			}
			else
			{
				fa[i][0]=-1;dep[i]=1;f[i]=i;
				F.push(i);
			}
		}
		else if(ff[i][len-1]=='r')
		{
			ff[i].erase(len-7,7);
			int v=ID[ff[i]];
			if(sex[v]==1)//男父親 
			{
				C[v].push_back(i);
			}
			else
			{
				fa[i][0]=-1;dep[i]=1;f[i]=i;
				F.push(i);
			}
		}
		
	}
	//for(int i=1;i<=n;i++) 
	init();int m;string x1,m1,x2,m2;
	cin>>m;
	while(m--)
	{
		cin>>m1>>x1>>m2>>x2;
		if(!ID.count(m1)||!ID.count(m2))
		{
			cout<<"NA\n";continue;
		}
		int a=ID[m1];int b=ID[m2];
		if(sex[a]==sex[b])
		{
			cout<<"Whatever\n";continue;
		}
		if(f[a]!=f[b])
		{
			cout<<"Yes\n";continue;
		}
		int lca=LCA(a,b);
		if(dep[a]-dep[lca]<4||dep[b]-dep[lca]<4)
		{
			cout<<"No\n";continue;
		}
		else
		{
			cout<<"Yes\n";continue;
		}
	}
	return 0;
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章