当前位置 博文首页 > 文章内容

    Luogu P4271 [USACO18FEB]New Barns P

    作者: 栏目:未分类 时间:2020-10-14 9:00:31

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    题意

    给一个一开始没有点的图,有 \(q\) 次操作,每次为加点连边或者查询一个点到连通块内所有点的距离最大值。

    \(\texttt{Data Range}:1\leq q\leq 10^5\)

    题解

    「雅礼集训 2017 Day5」远行很像的一个题,都是 LCT 维护直径。

    注意到树上一个点到其他点的距离最大值只可能在直径的两个端点处取到,而且又存在加边操作,所以可以直接使用 LCT 来维护。

    当合并两个连通块的时候需要在两个连通块各自的直径端点中选两个成为新的直径,需要讨论 \(6\) 种情况,这个暴力搞就行了。

    但是这个题不用这么麻烦。因为每一次合并的一边是一个点,所以只需要讨论两次就好了。

    同时,维护直径的两个端点和直径的距离可以使用并查集来维护,查询两点距离的话就先 split 把两个点的路径拉出来放到同一个 Splay 上,再用根节点的大小减 \(1\) 即可。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef int ll;
    typedef long long int li;
    const ll MAXN=3e5+51;
    ll n,c,d,x,fx,fy,mx,lx,rx;
    char op;
    ll ffa[MAXN],l[MAXN],r[MAXN],dist[MAXN];
    inline ll read()
    {
        register ll num=0,neg=1;
        register char ch=getchar();
        while(!isdigit(ch)&&ch!='-')
        {
            ch=getchar();
        }
        if(ch=='-')
        {
            neg=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            num=(num<<3)+(num<<1)+(ch-'0');
            ch=getchar();
        }
        return num*neg;
    }
    inline ll find(ll x)
    {
        return x==ffa[x]?x:ffa[x]=find(ffa[x]);
    }
    namespace LCT{
        struct Node{
            ll fa,rv,sz;
            ll ch[2];
        };
        struct LinkCutTree{
            Node nd[MAXN];
            ll st[MAXN];
            #define ls nd[x].ch[0]
            #define rs nd[x].ch[1]
            inline bool nroot(ll x)
            {
                return nd[nd[x].fa].ch[0]==x||nd[nd[x].fa].ch[1]==x;
            }
            inline void update(ll x)
            {
                nd[x].sz=nd[ls].sz+nd[rs].sz+1;
            }
            inline void reverse(ll x)
            {
                swap(ls,rs),nd[x].rv^=1;
            }
            inline void spread(ll x)
            {
                if(nd[x].rv)
                {
                    ls?reverse(ls):(void)1,rs?reverse(rs):(void)1;
                    nd[x].rv=0;
                }
            }
            inline void rotate(ll x)
            {
                ll fa=nd[x].fa,gfa=nd[fa].fa;
                ll dir=nd[fa].ch[1]==x,son=nd[x].ch[!dir];
                if(nroot(fa))
                {
                    nd[gfa].ch[nd[gfa].ch[1]==fa]=x;
                }
                nd[x].ch[!dir]=fa,nd[fa].ch[dir]=son;
                if(son)
                {
                    nd[son].fa=fa;
                }
                nd[fa].fa=x,nd[x].fa=gfa,update(fa);
            }
            inline void splay(ll x)
            {
                ll fa=x,gfa,cur=0;
                st[++cur]=fa;
                while(nroot(fa))
                {
                    st[++cur]=fa=nd[fa].fa;
                }
                while(cur)
                {
                    spread(st[cur--]);
                }
                while(nroot(x))
                {
                    fa=nd[x].fa,gfa=nd[fa].fa;
                    if(nroot(fa))
                    {
                        rotate((nd[fa].ch[0]==x)^(nd[gfa].ch[0]==fa)?x:fa);
                    }
                    rotate(x);
                }
                update(x);
            }
            inline void access(ll x)
            {
                for(register int i=0;x;x=nd[i=x].fa)
                {
                    splay(x),rs=i,update(x);
                }
            }
            inline void makeRoot(ll x)
            {
                access(x),splay(x),reverse(x);
            }
            inline ll findRoot(ll x)
            {
                access(x),splay(x);
                while(ls)
                {
                    spread(x),x=ls;
                }
                return x;
            }
            inline void split(ll x,ll y)
            {
                makeRoot(x),access(y),splay(y);
            }
            inline void link(ll x,ll y)
            {
                makeRoot(x);
                if(findRoot(y)!=x)
                {
                    nd[x].fa=y;
                }
            }
            #undef ls
            #undef rs
        };
    }
    LCT::LinkCutTree lct;
    inline ll getDist(ll x,ll y)
    {
        lct.split(x,y);
        return lct.nd[y].sz-1;    
    }
    int main()
    {
        n=read();
        for(register int i=1;i<=n;i++)
        {
            ffa[i]=l[i]=r[i]=i,lct.nd[i].sz=1;
        }
        for(register int i=0;i<n;i++)
        {
            cin>>op,x=read();
            if(op=='B')
            {
                ++c;
                if(x==-1)
                {
                    continue;
                }
                fx=c,fy=find(x),mx=dist[fx],lx=l[fx],rx=r[fx];
                if(mx<dist[fy])
                {
                    lx=l[fy],rx=r[fy],mx=dist[fy];
                }
                lct.link(c,x);
                if((d=getDist(l[fx],l[fy]))>mx)
                {
                    mx=d,lx=l[fx],rx=l[fy];
                }
                if((d=getDist(l[fx],r[fy]))>mx)
                {
                    mx=d,lx=l[fx],rx=r[fy];
                }
                l[fx]=lx,r[fx]=rx,dist[fx]=mx,ffa[fy]=fx;
            }
            if(op=='Q')
            {
                fx=find(x);
                printf("%d\n",max(getDist(x,l[fx]),getDist(x,r[fx])));
            }
        }
    }