最近公共祖先
描述
小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢?
“为什么呢?”小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边。
“嘿嘿,小Hi,你快过来看!”小Ho招呼道。
“你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来……什么!我们居然有同一个祖祖祖祖祖爷爷?”
“诶,真是诶……这个网站有点厉害啊。”小Hi不由感叹道。
“是啊,这是什么算法啊,这么厉害!”小Ho也附和道。
“别2,我说的是他能弄到这些数据很厉害,而人类的繁殖树这种层数比较浅的树对这类算法的要求可是简单的不得了,你都能写出来呢!”小Hi道。
“啊?我也能写出来?可是……该从哪开始呢?”小Ho困惑了。
小Ho要面临的问题是这样的,假设现在他知道了N个人的信息——他们的父亲是谁,他需要对于小Hi的每一次提问——两个人的名字,告诉小Hi这两个人的是否存在同一个祖先,如果存在,那么他们的所有共同祖先中辈分最低的一个是谁?
提示:不着急,慢慢来,另外我有一个问题:挖掘机技术哪家强?!
输入
每个测试点(输入文件)有且仅有一组测试数据。
每组测试数据的第1行为一个整数N,意义如前文所述。
每组测试数据的第2~N+1行,每行分别描述一对父子关系,其中第i+1行为两个由大小写字母组成的字符串Father_i, Son_i,分别表示父亲的名字和儿子的名字。
每组测试数据的第N+2行为一个整数M,表示小Hi总共询问的次数。
每组测试数据的第N+3~N+M+2行,每行分别描述一个询问,其中第N+i+2行为两个由大小写字母组成的字符串Name1_i, Name2_i,分别表示小Hi询问中的两个名字。
对于100%的数据,满足N<=10^2,M<=10^2, 且数据中所有涉及的人物中不存在两个名字相同的人(即姓名唯一的确定了一个人)。
输出
对于每组测试数据,对于每个小Hi的询问,输出一行,表示查询的结果:如果根据已知信息,可以判定询问中的两个人存在共同的祖先,则输出他们的所有共同祖先中辈分最低的一个人的名字,否则输出-1。
- 样例输入
-
11 JiaYan JiaDaihua JiaDaihua JiaFu JiaDaihua JiaJing JiaJing JiaZhen JiaZhen JiaRong JiaYuan JiaDaishan JiaDaishan JiaShe JiaDaishan JiaZheng JiaShe JiaLian JiaZheng JiaZhu JiaZheng JiaBaoyu 3 JiaBaoyu JiaLian JiaBaoyu JiaZheng JiaBaoyu LinDaiyu
- 样例输出
-
JiaDaishan JiaZheng -1
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 #include <string> 6 #include <map> 7 using namespace std; 8 string s1,s2; 9 map<string,string>mp; 10 map<string,int>vis; 11 void find(string s1,string s2){ 12 string tmp=s1; 13 vis.clear();//删除所有的元素 14 while(!tmp.empty()){ 15 vis[tmp]=1; 16 tmp=mp[tmp]; 17 } 18 tmp=s2; 19 while(!tmp.empty()&&!vis[tmp]){ 20 tmp=mp[tmp]; 21 } 22 if(!tmp.empty()){ 23 cout<<tmp<<endl; 24 } 25 else{ 26 cout<<"-1\n"; 27 } 28 } 29 int main() 30 { 31 int n,m; 32 scanf("%d",&n); 33 for(int i=0;i<n;i++){ 34 cin>>s1>>s2; 35 mp[s2]=s1; 36 } 37 scanf("%d",&m); 38 while(m--) 39 { 40 cin>>s1>>s2; 41 find(s1,s2); 42 } 43 return 0; 44 }
C: cltt的幸运数
时间限制: 1 s 内存限制: 128 MB题目描述
一棵树有n个节点,共m次查询,查询a,b的最近公共祖先是否为好数?若好数的数目是幸运数,输出YES,否则输出NO。
好数:可以表示为2的指数幂。如:1, 2,4,8,16,32,……
幸运数就是素数。
输入
nn(nn表示节点数目,接下来n−1n−1行,每行两个整数 x,yx,y 其中xx是yy的父节点)
mm(表示查询数目,接下来mm行,每行两个整数a,ba,b)
(1≤n≤105,1≤m≤10)(1≤n≤105,1≤m≤10)
输出
YESYES or NONO
样例输入
12 1 2 1 3 2 5 3 4 3 6 4 7 7 9 7 10 6 8 8 11 8 12 4 9 8 4 7 11 12 10 7
样例输出
YES
提示
来源
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #include<vector> #include <cstdlib> using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) int a, b, c, d; const int N = 2e5+5; pair<int,int>P; vector<int> ve[N]; vector<pair<int,int> > que[N]; int ans[50], pre[N],vis[N]; int t,n,m; int find(int x){ return pre[x]=pre[x]==x?x:find(pre[x]); } void init() { for(int i=1;i<=n;i++){ pre[i]=i; vis[i]=0; ve[i].clear(); que[i].clear(); } mem(ans,0); } void dfs(int u,int fa) { vis[u]=1; for(int i=0;i<ve[u].size();i++) { int v=ve[u][i]; dfs(v,u); } for(int j=0;j<que[u].size();j++){ int v=que[u][j].second; int vv=que[u][j].first;//一定用pair,不然无法对应每组的答案 if(vis[v]==1){ ans[vv]=find(v); } } pre[u]=fa; } bool prime(int x) { if(x==0||x==1) return false; if(x==2) return true; for(int i=2;i<=sqrt(x);i++){ if(x%i==0){ return false; } } return true; } int main() { scanf("%d",&n); init(); int x,y; for(int i=0;i<n-1;i++){ scanf("%d %d",&x,&y); ve[x].push_back(y); vis[y]=1; } scanf("%d",&m); for(int i=0;i<m;i++){ scanf("%d %d",&x,&y); que[x].push_back({i,y}); que[y].push_back({i,x}); } for(int i=1;i<=n;i++){ if(vis[i]==0){ memset(vis,0,sizeof(vis)); dfs(i,-1); break; } } int ret=0; for(int i=0;i<m;i++){ if(!(ans[i]&(ans[i]-1))) ret++; } if(prime(ret)){ printf("YES\n"); } else{ printf("NO\n"); } return 0; }
1 #include <iostream> 2 using namespace std; 3 const int N = 100009; 4 int n; 5 struct same{ 6 int vis,f; 7 }tree[N]; 8 void init() 9 { 10 for(int i = 1;i <= n;i++){ 11 tree[i].vis = 0; 12 tree[i].f = 0;//可能存在查询的数据没有公共祖先,此时认为为0 13 //因此再调用findf时,return 0 14 //如果令tree[i].f=i ,在查询23333333 和 152300 //时返回的就是152300,显然不对 15 } 16 } 17 int findf(int x,int y){ 18 for(int i=0;i<=N;i++) 19 { //因为是多次查询,每次都要令tree[i].vis==0 20 tree[i].vis=0; 21 } 22 tree[x].vis = 1; 23 while(x != tree[x].f){ 24 tree[x].vis = 1; 25 x = tree[x].f; 26 } 27 while(y != tree[y].f){ 28 if(tree[y].vis == 1){ 29 break; 30 } 31 y = tree[y].f; 32 } 33 return y; 34 } 35 int q[20]; 36 void init1(){ 37 q[0]=0;q[1]=1;//一般我们用x&(x-1)是否为0来判断x是不是2的指数幂 0&(-1)==0 38 for(int i=2;i<=18;i++) 39 q[i]=q[i-1]*2; 40 } 41 int t; 42 int main() 43 { 44 init1(); 45 int x,y,i,j,m; 46 int w=0; 47 cin>>n; 48 init(); 49 n--; 50 while(n--){ 51 cin>>x>>y; 52 tree[y].f = x; 53 } 54 cin>>m; 55 while(m--){ 56 cin>>x>>y;//x,y不一定小于100000,也可能在树中没有出现 57 i=findf(x,y); 58 for(j=0;j<=18;j++){ 59 if(q[j]==i){ 60 w++; 61 } 62 } 63 } 64 if(w==2||w==3||w==5||w==7)//1到10的素数只有2 3 5 7 65 cout<<"YES"<<endl; 66 else cout<<"NO"<<endl; 67 return 0; 68 }