首页 > 其他分享 >P4271 [USACO18FEB] New Barns P 题解

P4271 [USACO18FEB] New Barns P 题解

时间:2024-08-16 16:54:13浏览次数:12  
标签:tmp dep 题解 ll 200010 fa P4271 New 直径

题目传送门

前置知识

树的直径 | 最近公共祖先 | 并查集

解法

一个显而易见的结论:设点集 \(A\) 的直径的两个端点为 \(u_{1},v_{1}\),另一个点集 \(B\) 的直径的两个端点为 \(u_{2},v_{2}\),则 \(A \bigcup B\) 的直径端点一定是 \(\{ u_{1},v_{1},u_{2},v_{2} \}\) 中的两个。

还有另外一个结论:点集 \(A\) 中一个点 \(x\) 到点集中其他点中最远点的距离一定是到直径两个端点的距离取 \(\max\)。

  • 证明
    • 当 \(x\) 在直径上时,显然。
    • 当 \(x\) 不在直径上时,先走到直径上,就转化到了上述情况。

并查集维护连通块内直径的两个端点即可。

倍增来支持动态连边操作,做法同 luogu P3302 [SDOI2013] 森林

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
struct node
{
	ll nxt,to;
}e[200010];
ll head[200010],fa[200010][25],dep[200010],N,cnt=0;
void add(ll u,ll v)
{
	cnt++;
	e[cnt].nxt=head[u];
	e[cnt].to=v;
	head[u]=cnt;
}
void dfs(ll x,ll father)
{
	dep[x]=dep[father]+1;
	fa[x][0]=father;
	for(ll i=1;i<=N;i++)
	{
		fa[x][i]=fa[fa[x][i-1]][i-1];
	}
	for(ll i=head[x];i!=0;i=e[i].nxt)
	{
		if(e[i].to!=father)
		{
			dfs(e[i].to,x);
		}
	}
}
ll lca(ll x,ll y)
{
	if(dep[x]>dep[y])
	{
		swap(x,y);
	}
	for(ll i=N;i>=0;i--)
	{
		if(dep[x]+(1<<i)<=dep[y])
		{
			y=fa[y][i];
		}
	}
	if(x==y)
	{
		return x;
	}
	else
	{
		for(ll i=N;i>=0;i--)
		{
			if(fa[x][i]!=fa[y][i])
			{
				x=fa[x][i];
				y=fa[y][i];
			}
		}
		return fa[x][0];
	}
}
ll dis(ll x,ll y)
{
	return dep[x]+dep[y]-2*dep[lca(x,y)];
}
struct DSU
{
	ll fa[200010],pt[200010][2],tmp[5];
	void init(ll n)
	{
		for(ll i=1;i<=n;i++)
		{
			fa[i]=i;
			pt[i][0]=pt[i][1]=i;
		}
	}
	ll find(ll x)
	{
		return fa[x]==x?x:fa[x]=find(fa[x]);
	}
	void merge(int x,int y)
	{
		dfs(y,x);
		x=find(x);
		y=find(y);
		fa[y]=x;
		ll maxx=0;
		tmp[1]=pt[x][0];
		tmp[2]=pt[x][1];
		tmp[3]=pt[y][0];
		tmp[4]=pt[y][1];
		for(ll i=1;i<=4;i++)
		{
			for(ll j=i+1;j<=4;j++)
			{
				if(dis(tmp[i],tmp[j])>maxx)
				{
					maxx=dis(tmp[i],tmp[j]);
					pt[x][0]=tmp[i];
					pt[x][1]=tmp[j];
				}
			}
		}
	}
	ll ask(ll x)
	{
		ll y=find(x);
		return max(dis(x,pt[y][0]),dis(x,pt[y][1]));
	}
}D;
int main()
{
	ll q,x,n=0,i;
	char pd;
	cin>>q;
	N=log2(q)+1;
	D.init(q);
	for(i=1;i<=q;i++)
	{
		cin>>pd>>x;
		if(pd=='B')
		{
			n++;
			if(x==-1)
			{
				dfs(n,0);
			}
			else
			{
				D.merge(x,n);
			}
		}
		else
		{
			cout<<D.ask(x)<<endl;
		}
	}
	return 0;
}

标签:tmp,dep,题解,ll,200010,fa,P4271,New,直径
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18363216

相关文章

  • P8734 奇偶覆盖 题解
    Statement矩形面积并,但是覆盖奇数次、覆盖偶数次的面积要分别输出。Solution提供一种不费脑子的做法:首先离散化、扫描线,问题变成维护区间+1-1、询问全局有多少正数是奇数、多少正数是偶数。若去除“正数”的条件,这是很容易用一个标记下传的线段树维护的,区间分别维护0,1个......
  • Git 命令大全:详细讲解与常见问题解决方案
    目录1.Git基础命令2.分支管理命令3.远程仓库管理命令4.标签管理命令5.其他常用命令6.总结Git是目前最流行的分布式版本控制系统,它使得团队协作和代码管理变得更加高效。本文将详细介绍Git的常用命令及其应用场景,并针对可能遇到的问题提供解决方案。1.Git......
  • P8518 [IOI2021] 分糖果 题解
    DescriptionKhong阿姨正在给附近一所学校的学生准备\(n\)盒糖果。盒子的编号分别为\(0\)到\(n-1\),开始时盒子都为空。第\(i\)个盒子\((0\leqi\leqn-1)\)至多可以容纳\(c[i]\)块糖果(容量为\(c[i]\))。Khong阿姨花了\(q\)天时间准备糖果盒。在第\(j\)天......
  • [CEOI2009] photo 题解
    前言题目链接:洛谷。好多错解都被我叉了,所以来贡献一发正确的题解,并予以解释。题意简述平面上有\(n\)个点,现在要求用最少的底边在\(x\)轴上且面积小于等于\(S\)的矩形覆盖所有点,这些矩形可以重叠。问最少矩形数量。矩形顶点不必是整点。\(n\leq100\)。题目分析没什......
  • P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解
    题目传送门前置知识树链剖分|树的直径|最近公共祖先|并查集解法正着删边不太可做,考虑离线下来反着加边。一个显而易见的结论:设点集\(A\)的直径的两个端点为\(u_{1},v_{1}\),另一个点集\(B\)的直径的两个端点为\(u_{2},v_{2}\),则\(A\bigcupB\)的直径端点一定是......
  • 启动应用程序出现pcsvDevice.dll找不到问题解决
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个pcsvDevice.dll文件(挑选合适的版本文件)把......
  • P6109 [Ynoi2009] rprmq1 题解
    Description有一个\(n\timesn\)的矩阵\(a\),初始全是\(0\),有\(m\)次修改操作和\(q\)次查询操作,先进行所有修改操作,然后进行所有查询操作。一次修改操作会给出\(l_1,l_2,r_1,r_2,x\),代表把所有满足\(l_1\lei\ler_1\)且\(l_2\lej\ler_2\)的\(a_{i,j}\)元......
  • 题解:P10688 Buy Tickets
    题目大意排队时有人插队。输入格式给定队列长度$n$。接下来$n$行每行两个正整数,第一个表示该元素插入位置,另一个表示该元素的权值。输出格式按照顺序输出该位置元素的权值。注意事项输入的数据组数未知,需要一直输入,输入方法可以参考以下代码。while(cin>>n){......
  • 题解:P10781 【MX-J1-T1】『FLA - III』Spectral
    P10781【MX-J1-T1】『FLA-III』Spectral题解(非正解,正解应该是数学题。)这道题很简单,分析题意就可以得出核心代码:for(inti=1;i<=n;i++){ans=k+ans/i;}那么恭喜你获得$40$pts。为什么呢?因为题目需要的是最高温度,而烧碳获得的温度可能小于烧炭时减低的温度。简单说......
  • addEventHandler(MouseEvent.MOUSE_PRESSED, new Event
    canvas.addEventHandler(MouseEvent.MOUSE_DRAGGED,newEventHandler(){@Overridepublicvoidhandle(MouseEvente){doubledifX=e.getSceneX()-baseDrageX;doubledifY=e.getSceneY()-baseDrageY;baseDrageX=e.getSceneX();baseDrageY=e.getSceneY();......