列表

详情


NC24259. [USACO 2018 Feb P]New Barns

描述

Farmer John注意到他的奶牛们如果被关得太紧就容易吵架,所以他想开放一些新的牛棚来分散她们。

每当FJ建造一个新牛棚的时候,他会将这个牛棚用至多一条双向道路与一个现有的牛棚连接起来。为了确保他的奶牛们足够分散,他有时想要确定从某个特定的牛棚出发,到它能够到达的最远的牛棚的距离(两个牛棚之间的距离等于从一个牛棚出发到另一个之间必须经过的道路条数)。

FJ总共会给出Q)次请求,每个请求都是“建造”和“距离”之一。对于一个建造请求,FJ建造一个牛棚,并将其与至多一个现有的牛棚连接起来。对于一个距离请求,FJ向你询问从某个特定的牛棚通过一些道路到离它最远的牛棚的距离。保证询问的牛棚已经被建造。请帮助FJ响应所有的请求。

输入描述

第一行包含一个整数Q。以下Q行,每行包含一个请求。每个请求的格式都是“B p”或是“Q k”,分别告诉你建造一个牛棚并与牛棚p连接,或是根据定义求从牛棚kk出发最远的距离。如果p=−1,则新的牛棚不会与其他牛棚连接。否则,p是一个已经建造的牛棚的编号。牛棚编号从1开始,所以第一个被建造的谷仓是1号谷仓,第二个是2号谷仓,以此类推。

输出描述

对于每个距离请求输出一行。注意一个没有连接到其他牛棚的牛棚的最远距离为0.

示例1

输入:

7
B -1
Q 1
B 1
B 2
Q 3
B 2
Q 2

输出:

0
2
1

说明:

输入样例对应下面的牛棚网:

(1)
\
(2)---(4)
/
(3)

对于请求1,我们建造牛棚1。对于请求2,我们询问从1出发到最远连接的牛棚的距离。由于牛棚1没有与其他牛棚连接,所以回答是0。对于请求3,我们建造牛棚2并将其与牛棚1连接。对于请求4,我们建造牛棚3并将其与牛棚2连接。对于请求5,我们询问从3出发到最远连接的牛棚的距离。在这时,最远的是牛棚1,距离为2单位。对于请求6,我们建造牛棚4并将其与牛棚2连接。对于请求7,我们询问从2出发到最远连接的牛棚的距离。所有其他三个牛棚1,3,4都与2相距相同的距离1,所以这就是我们的回答。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 280ms, 内存消耗: 15340K, 提交时间: 2020-03-25 22:26:46

#include<iostream>
#include<cmath>
using namespace std;
int n,idx;
int l[100001],r[100001],fa[100001][37],dep[100001],g[100001],lg[100001];
int LCA(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	while(dep[x]>dep[y])
	{
		x=fa[x][lg[dep[x]-dep[y]]-1];
	 } 
	 if(x==y) return x;
	 for(int i=lg[dep[x]]-1;i>=0;i--)
	 {
	 	if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	 }
	 return fa[x][0];
}
int range(int x,int y)
{
	return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
void link(int x)
{
	++idx;
	if(x==-1)
	{
		g[idx]=idx;
		fa[idx][0]=idx;
		l[idx]=r[idx]=idx;
		return;
	}
	fa[idx][0]=x;
	dep[idx]=dep[x]+1;
	g[idx]=g[x];
	for(int i=1;(1<<i)<=dep[idx];i++)
	{
		fa[idx][i]=fa[fa[idx][i-1]][i-1];
	}
	int dis1=range(l[g[idx]],r[g[idx]]),dis2=range(idx,l[g[idx]]),dis3=range(idx,r[g[idx]]);
	if(dis2>dis1&&dis2>=dis3) r[g[idx]]=idx;
	if(dis3>dis1&&dis3>dis2) l[g[idx]]=idx;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		lg[i]=lg[i-1]+((1<<lg[i-1])==i);
	}
	for(int i=1;i<=n;i++)
	{
		char opt;
		int x;
		cin>>opt>>x;
		if(opt=='B')
		{
			link(x);
		}
		else
		{
			cout<<max(range(l[g[x]],x),range(x,r[g[x]]))<<endl;
		}
	}
	return 0;
}

C++14(g++5.4) 解法, 执行用时: 103ms, 内存消耗: 8676K, 提交时间: 2020-05-05 17:42:33

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int q,rt[N],f[N][20],dep[N],p1[N],p2[N],cnt;
inline int lca(int x,int y){
	if(dep[x]<dep[y])	swap(x,y);
	for(int i=17;i>=0;i--)	if(dep[f[x][i]]>=dep[y])	x=f[x][i];
	if(x==y)	return x;
	for(int i=17;i>=0;i--)	if(f[x][i]!=f[y][i])	x=f[x][i],y=f[y][i];
	return f[x][0];
}
inline int dis(int x,int y){return dep[x]+dep[y]-2*dep[lca(x,y)];}
signed main(){
	cin>>q;	char op[5];
	for(int i=1,x;i<=q;i++){
		scanf("%s %d",op,&x);
		if(op[0]=='B'){
			++cnt;
			if(x==-1)	dep[cnt]=1,rt[cnt]=cnt,p1[cnt]=p2[cnt]=cnt;
			else{
				dep[cnt]=dep[x]+1,f[cnt][0]=x,rt[cnt]=rt[x];
				for(int j=1;j<=17;j++)	f[cnt][j]=f[f[cnt][j-1]][j-1];
				int d1=dis(p1[rt[x]],p2[rt[x]]),d2=dis(cnt,p1[rt[x]]),d3=dis(cnt,p2[rt[x]]);
				if(d2>d1&&d2>=d3)	p2[rt[x]]=cnt;
				else if(d3>d1&&d3>=d2)	p1[rt[x]]=cnt;
			}
		}else	printf("%d\n",max(dis(p1[rt[x]],x),dis(p2[rt[x]],x)));
	}
	return 0;
}

上一题