[2018.07.21 T2] 离家出走

暂无链接

离家出走

【问题描述】

横看成岭侧成峰,远近高低各不同。

企鹅豆豆考试爆零了,心态爆炸的他准备离家出走。

贫穷的企鹅国有N座城市,一开始城市之间没有道路连接不能通行。随着时间推移,一些道路逐渐建立。但由于国家财力实在不足,所以随时随地任意两座城市最多只有一条路径可以互相到达。

每次豆豆考试爆炸,他都想从考场里跑到离考场最远的一个城市去。当然豆豆每次都会想知道,最远的且可以到达的城市离考场所在城市有多远?

奇妙的事情是,企鹅国的每一条道路长度都是1。

【输入格式】

第一行一个整数type,表示数据类型。

接下来第二行两个整数N,Q,表示城市个数和事件个数。

接下来Q行,先读入一个整数op,表示事件类型。

如果op=1,那么接着有两个整数u,v,表示城市u和城市v之间建立了一条新的道路。

如果op=2,那么接着有一个整数u,表示这次考试的考场在城市u,豆豆想知道最远的城市离考场有多远。

如果type=1,令上一次op=2时的答案为lastans,那么对于输入的每一个u或者v都需要异或上lastans。(lastans初始为0。)

如果type=0,那么不需要进行其余额外操作。

【输出格式】

对于每次op=2的询问,输出一行一个整数表示离考场最远的城市距离考场的距离。

【输入样例】

0
5 10
1 4 5
2 3
2 5
2 1
1 5 3
1 1 4
2 3
2 5
1 5 2
2 1

【输出样例】

0
3
2
3

【数据范围】

对于 20 % 的输入数据: N 5000 , Q 10000

对于 50 % 的输入数据: N 100000 , Q 200000

对于另外 20 % 的输入数据: t y p e = 0

100 % 的输入数据: N 300000 , Q 500000 ,道路的修建会满足,随时随地图中不存在环。

题解

因为要求离自己最远的点,又保证随时都是棵,所以我们可以想到树的直径(* 的我怎么没想到),离某个点最远的点一定是直径的两个端点中的一个。

所以我们大力 L C T 维护树的直径,当两棵树合并的时候,新的直径的两个端点一定是原来的四个端点中的两个,分 6 种情况讨论来更新直径端点即可。

出题人题解:

TIM截图20180723165635.png

LCT天下第一!!!!

代码
#include<bits/stdc++.h>
#define ls son[v][0]
#define rs son[v][1]
using namespace std;
const int M=3e5+5;
int dad[M],son[M][2],sum[M],le[M],ri[M],f[M],n,q,tot,typ;
char ch[5];
bool rev[M];
bool notroot(int v){return son[dad[v]][0]==v||son[dad[v]][1]==v;}
void up(int v){sum[v]=sum[ls]+sum[rs]+1;}
void turn(int v){swap(ls,rs);rev[v]^=1;}
void push(int v){if(!rev[v])return;if(ls)turn(ls);if(rs)turn(rs);rev[v]=0;}
void down(int v){if(notroot(v))down(dad[v]);push(v);}
void spin(int v)
{
    int f=dad[v],ff=dad[f],k=son[f][1]==v,w=son[v][!k];
    if(notroot(f))son[ff][son[ff][1]==f]=v;son[v][!k]=f,son[f][k]=w;
    if(w)dad[w]=f;dad[f]=v,dad[v]=ff;
    up(f);
}
void splay(int v)
{
    down(v);int f,ff;
    while(notroot(v))
    {
        f=dad[v],ff=dad[f];
        if(notroot(f))spin((son[f][0]==v)^(son[ff][0]==f)?v:f);
        spin(v);
    }
    up(v);
}
void access(int v){for(int f=0;v;v=dad[f=v])splay(v),rs=f,up(v);}
void beroot(int v){access(v),splay(v),turn(v);}
void link(int x,int y){beroot(x),dad[x]=y;}
int dis(int x,int y){beroot(x),access(y),splay(y);return sum[y]-1;}
int find(int v){return f[v]==v?v:f[v]=find(f[v]);}
void in(){scanf("%d%d%d",&typ,&n,&q);}
void ac()
{
    int op,x,y,last=0,l1,l2,l3,l4,l5,l6;
    for(int i=1;i<=n;++i)f[i]=le[i]=ri[i]=i;
    while(q--)
    {
        scanf("%d%d",&op,&x);
        if(typ)x^=last;
        if(op==1)
        {
            scanf("%d",&y);if(typ)y^=last;link(x,y);x=f[y]=find(x);
            l1=dis(le[x],ri[x]),l2=dis(le[y],ri[y]),l3=dis(le[x],ri[y]),l4=dis(le[y],ri[x]),l5=dis(le[x],le[y]),l6=dis(ri[y],ri[x]);
            if(l2>=l1&&l2>=l3&&l2>=l4&&l2>=l5&&l2>=l6)le[x]=le[y],ri[x]=ri[y];
            else if(l3>=l1&&l3>=l2&&l3>=l4&&l3>=l5&&l3>=l6)ri[x]=ri[y];
            else if(l4>=l1&&l4>=l2&&l4>=l3&&l4>=l5&&l4>=l6)le[x]=le[y];
            else if(l5>=l1&&l5>=l2&&l5>=l3&&l5>=l4&&l5>=l6)ri[x]=le[y];
            else if(l6>=l1&&l6>=l2&&l6>=l3&&l6>=l4&&l6>=l5)le[x]=ri[y];
        }
        else y=find(x),printf("%d\n",last=max(dis(le[y],x),dis(ri[y],x)));
    }
}
int main(){in();ac();}

猜你喜欢

转载自blog.csdn.net/shadypi/article/details/81170773
T2