codeforces div294 E 求到树上两点距离相同点的数目

很显然的lca树上倍增问题

1.两个点是相同点ans=n

2.两个点深度相同ans=n-size 包含x子树-size 包含y子树

3.两个点深度不同:则ans=深的那个向上走step/2步的size-向上走step/2-1的size

然后用倍增写啦==额我的solve函数好丑

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 int parent[200005][25];
 6 int now=0,next[200005],point[200005],head[200005];
 7 int depth[200005],size[200005];
 8 void add(int x,int y)
 9 {
10   next[++now]=head[x];
11   head[x]=now;
12   point[now]=y;
13 }
14 void dfs(int u,int pre,int deep)
15 {
16   parent[u][0]=pre;
17   depth[u]=deep;
18   size[u]=1;
19   for (int i=head[u];i;i=next[i])
20   {
21     int v=point[i];
22     if (v==pre) continue;
23     dfs(v,u,deep+1);
24     size[u]+=size[v];
25   }
26 }
27 void double_build(int n)
28 {
29   int i,j;
30   for (i=0;i<=20;i++)
31     for (j=1;j<=n;j++)
32       if (parent[j][i]<=0) parent[j][i+1]=0;
33       else parent[j][i+1]=parent[parent[j][i]][i];
34 }
35 int go_up(int u,int deep)
36 {
37   for (int k=0;k<=20;k++)
38     if ((deep>>k)&1) u=parent[u][k];
39   return u;
40 }
41 int solve(int n,int u,int v)
42 {
43   int i,step=0,x=u,y=v,f1,f2,f3,f4,judge=0;
44   if (depth[u]>depth[v]) swap(u,v),swap(x,y);
45   for (i=0;i<=20;i++)
46     if ((depth[v]-depth[u])>>i&1)
47     {
48       judge=1;
49       step-=depth[parent[v][i]]-depth[v];
50       v=parent[v][i];
51     }
52   if (u==v){
53     if (step%2) return 0;
54     f1=go_up(y,step/2);
55     f2=go_up(y,step/2-1);
56     return size[f1]-size[f2];
57   }
58   for (i=20;i>=0;i--)
59     if (parent[u][i]!=parent[v][i])
60     {
61       step-=2*(depth[parent[u][i]]-depth[u]);
62       u=parent[u][i];
63       v=parent[v][i];
64     }
65   step+=2;
66   if (step%2) return 0;
67   if (judge==0)
68   {
69     f2=go_up(y,step/2-1);
70     f3=go_up(x,step/2-1);
71     return n-size[f2]-size[f3];
72   }
73   f1=go_up(y,step/2);
74   f2=go_up(y,step/2-1);
75   return size[f1]-size[f2];
76 }
77 int main()
78 {
79   int n,x,y,i,m;
80   scanf("%d",&n);
81   memset(head,0,sizeof(head));
82   for (i=1;i<n;i++)
83   {
84     scanf("%d%d",&x,&y);
85     add(x,y); add(y,x);
86   }
87   dfs(1,0,0);
88   double_build(n);
89   scanf("%d",&m);
90   while (m--)
91   {
92     scanf("%d%d",&x,&y);
93     if (x==y) printf("%d\n",n);
94     else printf("%d\n",solve(n,x,y));
95   }
96   return 0;
97 }
View Code

题目链接:http://codeforces.com/contest/519/problem/E

转载于:https://www.cnblogs.com/xiao-xin/articles/4307759.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值