[2018.07.21 T2] 离家出走

39 篇文章 0 订阅
26 篇文章 0 订阅

暂无链接

离家出走

【问题描述】

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

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

贫穷的企鹅国有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 % 20\% 20%的输入数据: N ≤ 5000 , Q ≤ 10000 N≤5000,Q≤10000 N5000,Q10000

对于 50 % 50\% 50%的输入数据: N ≤ 100000 , Q ≤ 200000 N≤100000,Q≤200000 N100000,Q200000

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

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

题解

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

所以我们大力 L C T \mathcal{LCT} LCT维护树的直径,当两棵树合并的时候,新的直径的两个端点一定是原来的四个端点中的两个,分 6 6 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();}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值