题目链接:http://poj.org/problem?id=1470
题目大意:开始让你构造一棵树,然后有Q对u,v,最后让你求出每对u,v的最近祖先的编号和次数。
输入一个Q,然后有Q组(u,v)每组中间还有空格,tab等。但,稍稍想一下就能发现,Q组uv一共有Q*2个字符串,所以我们讲稿Q*2组str就可以了scanf("%s",str),然后处理每组str求得u,v
/*/
/*lca离线算法
/*/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<ctime>
#include<cmath>
#include<climits>
#define sf scanf
#define pf printf
#define cls(a) memset(a,0,sizeof(a))
#define _cls(a) memset(a,-1,sizeof(a))
using namespace std;
struct Edge_t{
int to,next;
}edge[3010];
int head[1010],et,qhead[1010],qt;//- -
int root[1010],ind[1010];//union & indgree
int anst[1010],color[1010];//ansector & color(visit)
//int res[400010];//respond
int num[1010];
vector<int>query[1010];
inline void adde(int u,int v){//add edge
edge[et].to=v,edge[et].next=head[u],head[u]=et++;
}
inline int Find(int x){ return root[x]=root[x]==x?x:Find(root[x]);}
void Union(int u,int v){
int ra=Find(u),rb=Find(v);
root[rb]=ra;
}
void LCA(int u){//从根节点开始
int v,e;
anst[u]=u;
for(e=head[u];e!=-1;e=edge[e].next){
LCA((v=edge[e].to));
Union(u,v);
anst[Find(u)]=u;
}
color[u]=1;
int s=query[u].size(),i=0;
for(;i<s;++i)
if(color[v=query[u][i]]){
//res[query[e].pos]=
num[anst[Find(v)]]++;
}
}
int deal(char *s,int v){
int i,ret=0;
if(v){
for(i=1;s[i];++i)
ret*=10,ret+=s[i]-'0';
}else{
for(i=0;s[i+1];++i)
ret*=10,ret+=s[i]-'0';
}
//pf("ret=%d\n",ret);
return ret;
}
int main(){
int n,m,i;
int t,u,v;
while(~sf("%d",&n)){
for(qt=et=0,i=1;i<=n;++i)
root[i]=i,head[i]=-1,ind[i]=0,anst[i]=-1,color[i]=0,query[i].clear(),num[i]=0;
for(i=0;i<n;++i){
sf("%d:(%d)",&u,&v);
//pf("u=%d v=%d\n",u,v);
while(v--){
sf("%d",&m);
adde(u,m);
ind[m]++;
}
}
int Q;
char str[20];
sf("%d",&Q);
Q<<=1;//一共Q*2个字符串
for(i=0;i<Q;++i){
sf("%s",str);
if(i&1) v=deal(str,0),query[u].push_back(v),query[v].push_back(u);
else u=deal(str,1);//后面那个1表示u,0表示v
}
for(i=1;i<=n;++i)
if(!ind[i]) break;
LCA(i);
for(i=1;i<=n;++i)
if(num[i]) pf("%d:%d\n",i,num[i]);
}
return 0;
}