LOJ 6038 「雅礼集训 2017 Day5」远行

题意

一开始有 \(n\) 个点的无边无向图,接下来有 \(q\) 次操作,每次操作分为以下两种:

  • 1 u v:将 \(u\)\(v\) 连边,保证 \(u\)\(v\) 不连通。

  • 2 u:询问 \(u\) 能到达的最远的点与 \(u\) 的距离。

要求强制在线。

\(\texttt{Data Range:}1\leq n\leq 3\times 10^5,1\leq q\leq 5\times 10^5\)

题解

注意到每一次加边操作后整个图是一个森林,所以考虑使用 \(\texttt{LCT}\) 来维护。

首先注意到一个结论:到树上任意一个点的距离最大的点一定是某条直径的端点,这个结论可以使用反证法来证明。

所以我们的目标是维护一个联通块的直径。

这个不是很难,维护一下某个点所在连通块的直径的两个端点,加边的时候讨论 \(u\)\(v\) 所在连通块中 \(6\) 种可能的直径,暴力选最大值即可。

维护这两个端点的时候我们可以使用并查集,减少码量和常数。

对于查询的话,枚举一下直径的两个端点取距离的最大值即可。

查询 \(u\)\(v\) 之间的距离的话就在 \(\texttt{LCT}\) 上维护一个子树大小,先 split(x,y),答案就是 \(sz_y-1\)。(我这里是以 \(y\) 为根的)

代码

#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=3e5+51;
ll type,n,qcnt,op,x,y,mx,lx,rx,fx,fy,d,lastAns;
ll ffa[MAXN],dist[MAXN],l[MAXN],r[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()
{
    type=read(),n=read(),qcnt=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<qcnt;i++)
    {
        op=read();
        if(op==1)
        {
            x=read()^(lastAns*type),y=read()^(lastAns*type);
            fx=find(x),fy=find(y),mx=dist[fx],lx=l[fx],rx=r[fx];
            if(mx<dist[fy])
            {
                lx=l[fy],rx=r[fy],mx=dist[fy];
            }
            lct.link(x,y);
            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];
            }
            if((d=getDist(r[fx],l[fy]))>mx)
            {
                mx=d,lx=r[fx],rx=l[fy];
            }
            if((d=getDist(r[fx],r[fy]))>mx)
            {
                mx=d,lx=r[fx],rx=r[fy];
            }
            ffa[fy]=fx,l[fx]=lx,r[fx]=rx,dist[fx]=mx;
        }
        if(op==2)
        {
            x=read()^(lastAns*type),y=find(x);
            printf("%d\n",lastAns=max(getDist(x,l[y]),getDist(x,r[y])));
        }
    }
}
posted @ 2020-06-03 21:20  Karry5307  阅读(198)  评论(0编辑  收藏  举报