题目描述
Bessie and Jonell are great friends. Since Farmer John scrambleswhere the cows graze every day, they are sometimes quite far from each otherand can't talk. The pastures and paths on FJ's farm form a 'tree' structure.Each pasture has exactly one distinct path to any other pasture, and eachpasture (except pasture #1, the 'root') also has a single parent node. Bessieand Jonell have decided that they will always meet at the closest pasture thatthat is both an ancestor of Jonell's pasture and of Bessie's pasture. FJcreated a map of his N (1 <= N <= 1,000) pastures (conveniently numbered1..N) that tells the parent P_i (1 <= P_i <= N) of each pasture exceptpasture 1, which has no parent. FJ has released his daily grazing schedule forthe next M (1 <= M <= 1,000) days, so Bessie and Jonell are decidingwhere they should meet each day for gossip. On day k, Bessie is in pasture B_k(1 <= B_k <= N) and Jonell is in pasture J_k (1 <= J_k <= N). Givena map and schedule, help Bessie and Jonell find their meeting places. Consider,for example, the following farm layout:
Pasture Parent Pasture
[1] --------- ----------------
/ | \ 1 ---
/ | \ 2 1
[2] [3] [6] 3 1
/ | \ 4 2
/ | \ 5 8
[4] [8] [9] 6 1
/ \ 7 8
/ \ 8 6
[5] [7] 9 6
Here are the meeting places that Bessie and Jonell would choose given a six day schedule of their initial grazing locations:
Bessie Jonell Meeting Place
-------- -------- ---------------
2 7 1
4 2 2
1 1 1
4 1 1
7 5 8
9 5 6
输入
* Line 1: Two space-separated integers: N and M * Lines 2..N: Linei contains a single integer that describes the parent of pasture i: P_i * LinesN+1..N+M: Line k+N describes Bessie and Jonell's respective pastures with twospace-separated integers: B_k and J_k
输出
* Lines 1..M: Line j contains the meeting place Bessie and Jonellwould use for line j+N of the input
样例输入
96
1
1
2
8
1
8
6
6
2 7
4 2
3 3
4 1
7 5
9 5
样例输出
1
2
3
1
8
6
题解:tarjan算法和RMQ倍增算法两种做法。
#include <cstdio> #include <cmath> #define N 1005 int n,m,k,first[N*2],next[N*2],v[N*2],s; int first1[N*2],next1[N*2],v1[N*2],ans[N]; int x,y,z,cnt,f[N],id[N*2]; bool vis[N]; using namespace std; inline int find(int x) { if (f[x]==x) return x; int t=find(f[x]); f[x]=t; return t; } inline void hb(int x,int y) { int xx=find(x),yy=find(y); if (xx!=yy) f[xx]=yy; } inline void tarjan(int root) { vis[root]=1; for (int i=first1[root];i;i=next1[i]) if (vis[v1[i]]) ans[id[i]]=find(v1[i]); for (int i=first[root];i;i=next[i]) if (!vis[v[i]]) { tarjan(v[i]); hb(v[i],root); } } int main() { scanf("%d%d",&n,&m); for (int i=2;i<=n;i++) { scanf("%d",&x); next[++cnt]=first[i]; first[i]=cnt; v[cnt]=x; next[++cnt]=first[x]; first[x]=cnt; v[cnt]=i; } cnt=0; for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); next1[++cnt]=first1[x]; first1[x]=cnt; v1[cnt]=y; id[cnt]=i; next1[++cnt]=first1[y]; first1[y]=cnt; v1[cnt]=x; id[cnt]=i; } for (int i=1;i<=n;i++) f[i]=i; tarjan(1); for (int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
//RMQ倍增算法 #include <cstdio> #include <cmath> #define N 1005 int n,m,k,first[N*2],next[N*2],v[N*2],s; int x,y,z,cnt,dep[N],f[N][20]; bool vis[N]; using namespace std; inline void dfs(int x,int k) { dep[x]=k; vis[x]=1; for (int i=first[x];i;i=next[i]) if (!vis[v[i]]) { f[v[i]][0]=x; dfs(v[i],k+1); } } inline int find(int x,int y) { if (dep[x]<dep[y]) { int t=x;x=y;y=t; } for (int i=log2(n);i>=0;i--) if (dep[f[x][i]]>=dep[y]) x=f[x][i]; if (x==y) return x; for (int i=log2(n);i>=0;i--) if (f[x][i]!=f[y][i]) { x=f[x][i]; y=f[y][i]; } return f[x][0]; } int main() { scanf("%d%d",&n,&m); for (int i=2;i<=n;i++) { scanf("%d",&x); next[++cnt]=first[i]; first[i]=cnt; v[cnt]=x; next[++cnt]=first[x]; first[x]=cnt; v[cnt]=i; } dfs(1,1); for (int j=1;j<=log2(n);j++) for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; for (int i=1;i<=m;i++) { scanf("%d%d",&x,&y); printf("%d\n",find(x,y)); } return 0; }