[Luogu P4271] [USACO18FEB] New Barns

洛谷传送门

题意翻译

Farmer John注意到他的奶牛们如果被关得太紧就容易吵架,所以他想开放一些新的牛棚来分散她们。 每当FJ建造一个新牛棚的时候,他会将这个牛棚用至多一条双向道路与一个现有的牛棚连接起来。为了确保他的奶牛们足够分散,他有时想要确定从某个特定的牛棚出发,到它能够到达的最远的牛棚的距离(两个牛棚之间的距离等于从一个牛棚出发到另一个之间必须经过的道路条数)。

FJ总共会给出 Q 1 Q 10 5 )次请求,每个请求都是“建造”和“距离”之一。对于一个建造请求,FJ建造一个牛棚,并将其与至多一个现有的牛棚连接起来。对于一个距离请求,FJ向你询问从某个特定的牛棚通过一些道路到离它最远的牛棚的距离。保证询问的牛棚已经被建造。请帮助FJ响应所有的请求。

输入输出格式

输入格式:

第一行一个正整数 Q

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

输出格式:

对于每个 Q 操作, 输出一行一个整数表示距离。 注意一个没有连接到其他牛棚的牛棚的最远距离为 0

输入输出样例

输入样例#1:

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

输出样例#1:

0
2
1

说明

The example input corresponds to this network of barns:

  (1) 
    \   
     (2)---(4)
    /
  (3)

In query 1, we build barn number 1.

In query 2, we ask for the distance of 1 to the farthest connected barn. Since barn 1 is connected to no other barns, the answer is 0.

In query 3, we build barn number 2 and connect it to barn 1.

In query 4, we build barn number 3 and connect it to barn 2.

In query 5, we ask for the distance of 3 to the farthest connected barn. In this case, the farthest is barn 1, which is 2 units away.

In query 6, we build barn number 4 and connect it to barn 2.

In query 7, we ask for the distance of 2 to the farthest connected barn.All three barns 1, 3, 4 are the same distance away, which is 1, so this is our answer.

解题分析

大概就是合并两个连通块, 查询连通块内点到其他点的最大距离。

注意到对于一个点, 在其连通块内与其距离最大的点一定为直径所在两点的一点, 所以我们可以在合并连通块的时候顺带维护直径所在的两个点。 当然这两个点也一定是原来四个点中的两个, 所以我们只需要求出两两之间距离即可。

对于这道题更简单, 因为每次只有一个点和一个连通块合并, 所以直接求两次距离即可。

怎么求距离?可以倍增LCA动态插入, 但是LCT大法好!!

每个点的权值设为1, s p l i t 后上面那个点的 s u m 1 即为距离…

总复杂度 O ( N l o g ( N ) )

代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define dad tree[now].fat
#define ls tree[now].son[0]
#define rs tree[now].son[1]
#define MX 100050
int q, top, arr;
int bel[MX], sta[MX], dis[MX];
struct Bound
{int a, b;}bd[MX];
struct Node
{
    int son[2], fat, sum;
    bool rev;
}tree[MX];
namespace DSU
{
    void reset()
    {
        for (R int i = 1; i <= q; ++i)
        bel[i] = i, tree[i].sum = 1, bd[i] = {i, i};
    }
    int find(const int &now) {return now == bel[now] ? now : bel[now] = find(bel[now]);}
}
namespace LCT
{
    IN bool get(const int &now) {return tree[dad].son[1] == now;}
    IN bool nroot(const int &now) {return tree[dad].son[1] == now || tree[dad].son[0] == now;}
    IN void pushup(const int &now) {tree[now].sum = tree[ls].sum + tree[rs].sum + 1;}
    IN void pushrev(const int &now) {std::swap(ls, rs), tree[now].rev ^= 1;}
    IN void pushdown(const int &now) {if(tree[now].rev) tree[now].rev = false, pushrev(ls), pushrev(rs);}
    IN void rotate(const int &now)
    {
        R bool dir = get(now);
        R int fa = dad, grand = tree[fa].fat;
        tree[fa].son[dir] = tree[now].son[dir ^ 1];
        tree[tree[now].son[dir ^ 1]].fat = fa;
        if(nroot(fa)) tree[grand].son[get(fa)] = now;
        tree[now].fat = grand;
        tree[now].son[dir ^ 1] = fa;
        tree[fa].fat = now;
        pushup(fa);
    }
    IN void splay(R int now)
    {
        int tmp = now, fa;
        sta[top = 1] = now;
        W (nroot(now)) sta[++top] = now = dad;
        W (top) pushdown(sta[top--]);
        now = tmp;
        W (nroot(now))
        {
            fa = dad;
            if(nroot(fa)) rotate(get(now) == get(fa) ? fa : now);
            rotate(now);
        }
        pushup(now);
    }
    IN void access(R int now)
    {
        for (R int x = 0; now; x = now, now = dad)
        {splay(now); rs = x; pushup(now);}
    }
    IN void makeroot(const int &now)
    {access(now), splay(now), pushrev(now);}
    IN void link(const int &x, const int &y)
    {makeroot(x); tree[x].fat = y;}
    IN void split(const int &x, const int &y)
    {makeroot(x); access(y); splay(y);}
}
int main(void)
{
    scanf("%d", &q); DSU::reset();
    char buf[3]; int a, tar, mx1, mx2;
    W (q--)
    {
        scanf("%s%d", buf, &a);
        if(buf[0] == 'B')
        {
            ++arr;
            if(a == -1) continue;
            else
            {
                tar = DSU::find(a);
                LCT::link(arr, a);
                bel[arr] = tar;
                LCT::split(arr, bd[tar].a);
                mx1 = tree[bd[tar].a].sum - 1;
                LCT::split(arr, bd[tar].b);
                mx2 = tree[bd[tar].b].sum - 1;
                if(mx1 > dis[tar]) dis[tar] = mx1, bd[tar] = {arr, bd[tar].a};
                if(mx2 > dis[tar]) dis[tar] = mx2, bd[tar] = {arr, bd[tar].b};
            }
        }
        else
        {
            tar = DSU::find(a);
            LCT::split(a, bd[tar].a);
            mx1 = tree[bd[tar].a].sum - 1;
            LCT::split(a, bd[tar].b);
            mx2 = tree[bd[tar].b].sum - 1;
            printf("%d\n", std::max(mx1, mx2));
        }
    }
}

猜你喜欢

转载自blog.csdn.net/lpa20020220/article/details/81176186