POJ 1470/PKU 1470 Closest Common Ancestors __LCA
题目链接: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; }