标签:
树形DP+LCA+思路。这题可真是有点难度......所以准备详细写一下题解。
题意:给一颗无根树,有Q次询问,每次询问指定一个根节点X,然后让你计算Y节点的儿子和子孙中,编号最小的节点是多少。
我们先以1为根节点进行一次树形DP,记录下每个节点的儿子和子孙中,编号最小的节点是多少。
首先很容易想到一种情况:就是X和Y的最近公共祖先不是Y,这个时候,结果和以1为根节点建树是一模一样的,因为把X提到最上面去,不会影响到Y的子树的情况。
剩余的情况就是X和Y的最近公共祖先等于Y(这种情况就是X在Y的子树上),这个时候,如果把X提上去,那么无法直接从以1为根节点DP的结果得出答案,我们需要进行推导。这个时候,需要分两种情况。若Y==1,这个时候把X提上去,就好比从1连出来那么多的节点的子树中,X所在子树不再是Y的后代,如果X所在子树是最小值存在的子树,那么输出次小值,否则输出最小值。若Y!=1,这个时候,也是X所在子树不成为Y的后代,那么依然需要知道X所在子树是否是最小值存在的子树,还需要知道Y的父亲的情况,因为这个时候,Y的父亲那边的所有点成为了Y的子树。
综上所述,树形DP进行DFS的时候,我们需要记录每个子树的儿子最小值、次小值,后代最小值、次小值,每个节点的父亲节点的编号。
还需要o(1)判断两点是否在一条链上,这个可以通过时间戳来判断。
有了上述信息,在进行完先以1为根节点的DP之后,每一次询问,都可以在o(1)内得到答案。
代码写的又臭又长....还是不要看了。
#include <stdio.h> #include <algorithm> #include <string.h> #include <queue> #include <stack> #include <map> #include <vector> using namespace std; const int maxn=100000+10; const int INF=0x7fffffff; int n,m; vector<int>tree[maxn]; bool vis[maxn]; int MinSon[maxn],CiSon[maxn]; int MinDes[maxn],CiDes[maxn]; int belong[maxn]; int Fa; int MinSonPos; int MinDesPos; int CiSonPos; int CiDesPos; struct P { int a,b; }pp[maxn]; bool cmp(const P&a,const P&b) { return a.b<b.b;} int par[maxn]; int dfnIn[maxn],dfnOut[maxn]; int time; int fa[maxn],l[maxn],p[maxn][25]; int top, sun; struct Edge{ int v; Edge* next; }*adj[maxn], edge[maxn << 1]; void add(int u, int v){ Edge* p = &edge[++top]; p -> v = v; p -> next = adj[u]; adj[u] = p; } void DFS(int u, int father, int depth){ fa[u] = father; l[u] = depth; for(Edge* p = adj[u]; p; p = p -> next){ int v = p -> v; if(v == father) continue; DFS(v, u, depth + 1); } } void init_p(int n){ int log = 0; for(; (1 << log) < n; log++); log--; for(int i = 1; i <= n; i++){ for(int j = 0; j <= log; j++) p[i][j] = -1; } for(int i = 1; i <= n; i++) p[i][0] = fa[i]; for(int j = 1; j <= log; j++){ for(int i = 1; i <= n; i++) if(p[i][j - 1] != -1) p[i][j] = p[p[i][j - 1]][j - 1]; } } int query(int a, int b){ int log, i; if(l[a] < l[b]) swap(a, b); for(log = 1; (1 << log) <= l[a]; log++); log--; for(i = log; i >= 0; i--){ if(l[a] - (1 << i) > l[b]){ a = p[a][i]; } } sun = a; if(fa[a] == b) return b; a = fa[a]; for(i = log; i >= 0; i--) if(p[a][i] != -1 && p[a][i] != p[b][i]){ a = p[a][i]; b = p[b][i]; } return fa[a]; } void init() { top = 0;time=0; for(int i = 1; i <= n; i++) adj[i] = 0; memset(vis,0,sizeof vis); for(int i=1;i<=n;i++) MinSon[i]=INF,MinDes[i]=INF; for(int i=1;i<=n;i++) CiSon[i]=INF,CiDes[i]=INF; for(int i=1;i<=n;i++) tree[i].clear(); } void read() { for(int i=1; i<n; i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); tree[u].push_back(v); tree[v].push_back(u); } } void dfs(int now) { dfnIn[now]=++time; if(now!=1) belong[now]=Fa; bool fail=1; for(int i=0;i<tree[now].size();i++) if(!vis[tree[now][i]]) fail=0; if(fail) { dfnOut[now]=++time; return; } int *ff= new int[tree[now].size()+5]; for(int i=0;i<tree[now].size();i++) ff[i]=0; for(int i=0;i<tree[now].size();i++) { if(vis[tree[now][i]]) continue; ff[i]=1; par[tree[now][i]]=now; if(now==1) Fa=tree[now][i]; vis[tree[now][i]]=1; dfs(tree[now][i]); MinSon[now]=min(MinSon[now],tree[now][i]); MinDes[now]=min(MinDes[now],MinDes[tree[now][i]]); } MinDes[now]=min(MinDes[now],MinSon[now]); for(int i=0;i<tree[now].size();i++) { if(!ff[i]) continue; if(tree[now][i]!=MinSon[now]) CiSon[now]=min(CiSon[now],tree[now][i]); if(MinDes[tree[now][i]]!=MinDes[now]) CiDes[now]=min(CiDes[now],MinDes[tree[now][i]]); if(CiDes[tree[now][i]]!=MinDes[now]) CiDes[now]=min(CiDes[now],CiDes[tree[now][i]]); } if(MinSon[now]!=MinDes[now]) CiDes[now]=min(CiDes[now],MinSon[now]); dfnOut[now]=++time; delete []ff; } void work() { memset(vis,0,sizeof vis); DFS(1, -1, 0); init_p(n); vis[1]=1;dfs(1); MinSonPos=INF; MinDesPos=INF; CiSonPos=INF; CiDesPos=INF; for(int i=0;i<tree[1].size();i++) MinSonPos=min(MinSonPos,tree[1][i]); for(int i=0;i<tree[1].size();i++) { if(tree[1][i]==MinSonPos) continue; CiSonPos=min(CiSonPos,tree[1][i]); } int yy=0; for(int i=0;i<tree[1].size();i++) { pp[yy].a=tree[1][i]; pp[yy++].b=min(tree[1][i],MinDes[tree[1][i]]); } sort(pp,pp+yy,cmp); MinDesPos=pp[0].a; if(yy>=1) CiDesPos=pp[1].a; for(int i=1;i<=m;i++) { int X,Y; scanf("%d%d",&X,&Y); int U=query(X,Y); if(U!=Y) { if(MinDes[Y]==INF) printf("no answers!\n"); else printf("%d %d\n",MinSon[Y],MinDes[Y]); } else { if(Y==1) { int ans1,ans2; int be=belong[X]; if(MinSonPos==be) ans1=CiSonPos; else ans1=MinSonPos; if(MinDesPos==be) ans2=CiDesPos; else ans2=MinDesPos; if(ans1==INF||ans2==INF) printf("no answers!\n"); else printf("%d %d\n",ans1,min(ans2,MinDes[ans2])); } else { int ans=INF; if(dfnIn[X]>=dfnIn[MinSon[Y]]&&dfnOut[X]<=dfnOut[MinSon[Y]]) ans=min(CiSon[Y],par[Y]); else if(dfnIn[MinSon[Y]]>=dfnIn[X]&&dfnOut[MinSon[Y]]<=dfnOut[X]) ans=min(CiSon[Y],par[Y]); else ans=min(MinSon[Y],par[Y]); printf("%d 1\n",ans); } } } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); init(); read(); work(); printf("\n"); } return 0; }
标签:
原文地址:http://www.cnblogs.com/zufezzt/p/5187261.html