标签:
假设树的直径的两个端点为p0,p1。如果对于一次询问(v,k)存在点q满足要求,那么q必然在v到p0或v到p1的路径上。
剩下的就是在树上寻找p了。倍增就好了。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <stack> #include <map> #define LL long long #define ULL unsigned long long #define INF 0x3f3f3f3f using namespace std; const int MAXN = 20010; const int MAXM = 15; struct N { int v,next; }edge[2*MAXN]; int head[MAXN]; int Top; void Link(int u,int v) { edge[Top].v = v; edge[Top].next = head[u]; head[u] = Top++; } int pa[2][MAXN][MAXM]; int dep[2][MAXN]; void InitDepFa(int s,int lay,int pre = -1,int d = 0) { dep[lay][s] = d; pa[lay][s][0] = pre; for(int p = head[s];p != -1; p = edge[p].next) { if(edge[p].v != pre) InitDepFa(edge[p].v,lay,s,d+1); } } void InitPa(int n,int lay) { int i,j; for(j = 1;j < MAXM; ++j) { for(i = 1;i <= n; ++i) { if(pa[lay][i][j-1] != -1) pa[lay][i][j] = pa[lay][pa[lay][i][j-1]][j-1]; else pa[lay][i][j] = -1; } } } int QueryKthPoint(int u,int k,int lay) { for(int i = MAXM-1;i >= 0 && k; --i) { if(k >= (1<<i)) u = pa[lay][u][i],k -= (1<<i); } return u; } queue<int> q; bool mark[MAXN]; int bfs(int s) { memset(mark,false,sizeof(mark)); mark[s] = true; q.push(s); while(q.empty() == false) { s = q.front(); q.pop(); for(int p = head[s] ;p != -1; p = edge[p].next) if(mark[edge[p].v] == false) q.push(edge[p].v),mark[s] = true; } return s; } int main() { int i,u,v,n,m,a,k; while(scanf("%d %d",&n,&m) != EOF) { memset(head,-1,sizeof(head)); Top = 0; for(i = 1;i < n; ++i) { scanf("%d %d",&u,&v); Link(u,v); Link(v,u); } u = bfs(v = bfs(1)); InitDepFa(u,0); InitPa(n,0); InitDepFa(v,1); InitPa(n,1); while(m--) { scanf("%d %d",&a,&k); if(dep[0][a] >=k) printf("%d\n",QueryKthPoint(a,k,0)); else if(dep[1][a] >= k) printf("%d\n",QueryKthPoint(a,k,1)); else printf("0\n"); } } return 0; }
标签:
原文地址:http://blog.csdn.net/zmx354/article/details/45076731