jzoj 5012. 【NOI2017模拟3.13】远行 启发式合并

来源:互联网 发布:微信链接网络出错1003 编辑:程序博客网 时间:2024/04/29 18:11

题意

给n个点,要求资瓷q个操作:
1 x y表示在x到y之间连一条边
2 x表示求x到其能到达的最远的点的距离
满足任意时刻该图为一片森林。
n<=300000,q<=500000,强制在线

分析

显然每个点能到的最远的点为该点所在树的直径的其中一个端点,那么我们只要维护树的直径即可。
若两棵树合并,那么新直径的两个端点必然是两棵树的旧直径的端点,维护起来就十分的爽。
但是距离要怎么求呢?
一开始想的是用lct来维护,正解貌似也是lct,但是由于其码量和常数都十分巨大,蒟蒻看得瑟瑟发抖,于是就打了启发式合并。
O(nlog2n+qlogn)
lctO((n+q)logn)

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define N 300005using namespace std;int n,q,last[N],fa[N][20],dep[N],f[N],size[N],cnt;struct weight{int x,y,len;}wei[N];struct edge{int to,next;}e[N*2];int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void addedge(int u,int v){    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;}int find(int x){    if (f[x]==x) return x;    f[x]=find(f[x]);    return f[x];}void build(int x){    dep[x]=dep[fa[x][0]]+1;    for (int i=1;i<=18;i++) fa[x][i]=fa[fa[x][i-1]][i-1];    for (int i=last[x];i;i=e[i].next)    {        if (e[i].to==fa[x][0]) continue;        fa[e[i].to][0]=x;        build(e[i].to);    }}int get_len(int x,int y){    int x1=x,y1=y;    if (dep[x]<dep[y]) swap(x,y);    for (int i=18;i>=0;i--)        if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];    if (x==y) return dep[x1]+dep[y1]-2*dep[x];    for (int i=18;i>=0;i--)        if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];    return dep[x1]+dep[y1]-2*dep[fa[x][0]];}int main(){    freopen("hike.in","r",stdin);freopen("hike.out","w",stdout);    int ty=read();    n=read();q=read();    int lastans=0;    for (int i=1;i<=n;i++) wei[i].x=wei[i].y=f[i]=i,size[i]=1,dep[i]=1;    while (q--)    {        int op=read();        if (op==1)        {            int x=read(),y=read();            if (ty) x^=lastans,y^=lastans;            int fx=find(x),fy=find(y);            if (size[fx]>size[fy]) swap(x,y),swap(fx,fy);            f[fx]=fy;size[fy]+=size[fx];            addedge(x,y);            fa[x][0]=y;            build(x);            int a[2],b[2];            a[0]=wei[fx].x;a[1]=wei[fx].y;b[0]=wei[fy].x;b[1]=wei[fy].y;            if (wei[fx].len>wei[fy].len) wei[fy].x=a[0],wei[fy].y=a[1],wei[fy].len=wei[fx].len;            for (int i=0;i<=1;i++)                for (int j=0;j<=1;j++)                {                    int w=get_len(a[i],b[j]);                    if (w>wei[fy].len) wei[fy].len=w,wei[fy].x=a[i],wei[fy].y=b[j];                }        }        else        {            int x=read();            if (ty) x^=lastans;            int y=find(x);            lastans=max(get_len(x,wei[y].x),get_len(x,wei[y].y));            printf("%d\n",lastans);        }    }    return 0;}
0 0
原创粉丝点击