[lca][倍增] Bzoj P5192 New Barns

Description

FarmerJohn注意到他的奶牛们如果被关得太紧就容易吵架,所以他想开放一些新的牛棚来分散她们。每当FJ建造一
个新牛棚的时候,他会将这个牛棚用至多一条双向道路与一个现有的牛棚连接起来。为了确保他的奶牛们足够分散
,他有时想要确定从某个特定的牛棚出发,到它能够到达的最远的牛棚的距离(两个牛棚之间的距离等于从一个牛
棚出发到另一个之间必须经过的道路条数)。FJ总共会给出Q(1≤Q≤10^5)次请求,每个请求都是“建造”和“
距离”之一。对于一个建造请求,FJ建造一个牛棚,并将其与至多一个现有的牛棚连接起来。对于一个距离请求,
FJ向你询问从某个特定的牛棚通过一些道路到离它最远的牛棚的距离。保证询问的牛棚已经被建造。请帮助FJ响应
所有的请求。
 

Input

第一行包含一个整数Q
以下Q行,每行包含一个请求。每个请求的格式都是“B p”或是“Q k”
分别告诉你建造一个牛棚并与牛棚p连接,或是根据定义求从牛棚k出发最远的距离。
如果p=-1,则新的牛棚不会与其他牛棚连接。
否则,p是一个已经建造的牛棚的编号。
牛棚编号从1开始,所以第一个被建造的谷仓是1号谷仓,第二个是2号谷仓,以此类推。
 

Output

对于每个距离请求输出一行。注意一个没有连接到其他牛棚的牛棚的最远距离为0

 

Sample Input

7
B -1
Q 1
B 1
B 2
Q 3
B 2
Q 2

Sample Output

0
2
1
输入样例对应下面的牛棚网:
(1)
\
(2)---(4)
/
(3)
对于请求1,我们建造牛棚1。对于请求2,我们询问从1出发到最远连接的牛棚的距离。由于牛棚1没有与其他牛棚
连接,所以回答是0。对于请求3,我们建造牛棚2并将其与牛棚1连接。对于请求4,我们建造牛棚3并将其与牛棚2
连接。对于请求5,我们询问从3出发到最远连接的牛棚的距离。在这时,最远的是牛棚1,距离为2单位。对于请求
6,我们建造牛棚4并将其与牛棚2连接。对于请求7,我们询问从2出发到最远连接的牛棚的距离。所有其他三个牛
棚1,3,4都与2相距相同的距离1,所以这就是我们的回答。

 

题解

  • 显然,从一个点出发到的最远距离就是直径
  • 加入一个点后,最远距离两个端点中一定有一个端点是原来直径上的端点
  • 那么显然我们就可以用lct来维护每个节点的直径,就可以做了
  • 不过作为我这种懒人是能水就水的(逃)
  • 那么我们可以在每个节点维护直径的两个端点,然后加入点时再用lca更新,也用lca求最远距离
  • 判断一个点在哪个直径上,只用一个数组将该直径所经过的所有点打上标记就好了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cmath>
 4 #include <algorithm>
 5 #include <cstring>
 6 using namespace std;
 7 const int N=1e5+10;
 8 struct node{int l,r;}t[N];
 9 int n,a1,a2,a3,top,deep[N],f[N][17],p[N];
10 char ch;
11 int lca(int x,int y)
12 {
13     int i,dis=0;
14     if (deep[x]>deep[y]) swap(x,y);
15     for (int i=deep[y]-deep[x],j=0;i>0;i>>=1,j++) if (i&1) dis+=pow(2,j),y=f[y][j];
16     if (x==y) return dis;
17     for (i=0;(1<<i)<=deep[x];i++);
18     for (;i>=0;i--) if ((1<<i)<=deep[x]&&f[x][i]!=f[y][i]) dis+=pow(2,i+1),x=f[x][i],y=f[y][i]; 
19     return dis+2;
20 }
21 int main()
22 {
23     scanf("%d",&n);
24     for (int i=1,x;i<=n;i++)
25     {
26         cin>>ch>>x;
27         if (ch=='Q') a1=p[x],a2=lca(x,t[a1].l),a3=lca(x,t[a1].r),printf("%d\n",max(a2,a3));
28         else 
29         {
30             ++top;
31             if (x==-1)
32             {
33                 p[top]=top,deep[top]=0,f[top][0]=top,t[top].l=t[top].r=top;
34                 continue;
35             }
36             f[top][0]=x,deep[top]=deep[x]+1,p[top]=p[x];
37             for (int i=1;(1<<i)<=deep[top];i++) f[top][i]=f[f[top][i-1]][i-1];
38             int o=p[x],dis1=lca(top,t[o].l),dis2=lca(t[o].l,t[o].r);
39             if (dis1>dis2) t[o].r=top;
40             int dis3=lca(top,t[o].r);
41             if (dis3>dis2) t[o].l=top;
42         }
43     }
44 }

 

转载于:https://www.cnblogs.com/Comfortable/p/11133219.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值