DTOJ#5203. 小 T 与灵石

传送门

穿过繁花森林,小 T 来到一个瀑布前。小 T 像往常一样戏水,但今天小 T 在瀑布后发现了一个密室。小 T 小心翼翼地走了进去,看见一块灵石悬浮在空中,小 T 突然明白了为什么这座山上的花开得这么茂盛。小 T 正想上前查看,却被一股神秘的力量挡住,紧接着不知从何处传来了声音:“想要接近我,先回答一个问题……”

给你一棵 n n n 个结点的有根树,树的根为 1 1 1 。一共有 q q q 次操作,第 i i i 次操作选定 k i k_i ki 个点 p 1 , p 2 , … , p k i p_1, p_2,\dots, p_{k_i} p1,p2,,pki ,对每个点 x x x 定义 f x , i = max ⁡ j = 1 k i { d i s t ( x , p j ) } f_{x,i} = \max^{k_i}_{j=1} \{dist(x, p_j )\} fx,i=maxj=1ki{dist(x,pj)} ,其中 d i s t ( x , y ) dist(x, y) dist(x,y) 表示树上 x , y x, y x,y 两点间最短路经过的边数。再对每个点 x x x 定义 g x = min ⁡ i = 1 q { f x , i } g_x = \min^q_{i=1} \{f_{x,i}\} gx=mini=1q{fx,i} ,对于每个点你需要求出 g x g_x gx

听完这个问题后,小 T 顿时就蒙圈了。但小 T 对灵石非常地好奇,你能帮帮小 T 解决这个问题吗?

输入共 ( q + 3 ) (q + 3) (q+3) 行。

第一行一个正整数 n n n ,表示树上的结点数。

第二行 ( n − 1 ) (n − 1) (n1) 个正整数,第 i i i 个数表示 i + 1 i + 1 i+1 号结点的父亲 a i + 1 a_{i+1} ai+1

第三行一个正整数 q q q ,表示操作次数。

接下来 q q q 行,每行最开始有一个正整数 k i k_i ki,接下来输入 k i k_i ki 个互不相同的正整数 p 1 , p 2 , … , p k i p_1, p_2,\dots, p_{k_i} p1,p2,,pki ,其意义见【题目描述】。

输出 n n n 行,第 i i i 行输出一个整数 g i g_i gi ,其意义见【题目描述】。

样例输入
8
1 1 2 2 3 4 4
2
3 5 6 7
2 2 8

样例输出
3
2
4
1
3
5
2
2
样例解释

第一次操作的 f f f 值为 3 , 3 , 4 , 4 , 4 , 5 , 5 , 5 3, 3, 4, 4, 4, 5, 5, 5 3,3,4,4,4,5,5,5 ;第二次操作的 f f f 值为 3 , 2 , 4 , 1 , 3 , 5 , 2 , 2 3, 2, 4, 1, 3, 5, 2, 2 3,2,4,1,3,5,2,2

对于所有测试点,满足 1 ≤ n , q ≤ 3 × 1 0 5 , ∑ i = 1 q k i ≤ 1 0 6 , 1 ≤ a i , p i , k i ≤ n 1 \leq n, q \leq 3 \times 10^5,\sum^q_{i=1} k_i \leq 10^6,1 \leq a_i, p_i, k_i \leq n 1n,q3×105,i=1qki106,1ai,pi,kin

每个子任务的具体限制见下表:

子任务编号分值 n ≤ n\leq n ∑ i = 1 q k i ≤ \sum^q_{i=1}k_i \leq i=1qki特殊限制
1 1 1 10 10 10 400 400 400 400 400 400
2 2 2 20 20 20 3000 3000 3000 3000 3000 3000
3 3 3 20 20 20 3 × 1 0 5 3 \times 10^5 3×105 1 0 6 10^6 106树是一条链
4 4 4 20 20 20 1 0 5 10^5 105 1 0 5 10^5 105
8 8 8 30 30 30 3 × 1 0 5 3 \times 10^5 3×105 1 0 6 10^6 106

成都七中 noip2020模拟

首先,树上最远点必须想到直径,这时我们发现无论多少个点,只有直径端点有用,所以我们动态维护直径。
但这题卡常,所以我们用 S T ST ST O ( 1 ) O(1) O(1) 查询 l c a lca lca

#include<bits/stdc++.h>
#define N 300005
using namespace std;
inline char GET_CHAR ( void )
{
    static char buf[1<<23],*p1=buf,*p2=buf;
    return p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2) ? EOF : *p1++;
}
inline int read ( void )
{
	int x=0;char ch;
	while ( !isdigit(ch=GET_CHAR()) ) ;
	for ( x=ch^48;isdigit(ch=GET_CHAR()); ) x=(x<<1)+(x<<3)+(ch^48);
	return x;
}
vector<int> to[N];
int ans[N],dep[N],f[N<<1][20],T=19,qt,e[21],pos[N<<1],tt[N][20];
void dfs(int x,int las){
	f[++qt][0]=x;
	pos[x]=qt;
	for(int i=0;i<(int)to[x].size();++i){
		int y=to[x][i];
		if(y==las)continue;
		dep[y]=dep[x]+1;
		tt[y][0]=x;
		for(int j=1;j<=T;++j)tt[y][j]=tt[tt[y][j-1]][j-1];
		dfs(y,x);
		f[++qt][0]=x;
	}
}
inline int get(int x,int y){
	x=pos[x],y=pos[y];
	if(x>y)swap(x,y);
	int k=(int)(log((double)(y-x+1))/log(2.0));
	return (dep[f[x][k]]<dep[f[y-e[k]+1][k]])?f[x][k]:f[y-e[k]+1][k];
}
inline int calc(int x,int y){
	return dep[x]+dep[y]-2*dep[get(x,y)];
}
inline int tow(int x,int de){
	for(int i=T;i+1;--i)if(dep[tt[x][i]]>=de)x=tt[x][i];
	return x;
}
char ls[3005];
void ot(int x){
	if(x==0) {putchar('0'),putchar('\n');return;}
	if(x<0) putchar('-'),x=-x;
	int temp=0;
	while(x) ls[++temp]=x%10+'0',x/=10;
	while(temp) putchar(ls[temp--]);
	putchar('\n');
}
inline void dfs2(int x,int las){
	for(int i=0;i<(int)to[x].size();++i){
		int y=to[x][i];
		if(y==las)continue;
		dfs2(y,x);
		ans[x]=min(ans[x],ans[y]+1);
	}
}
inline void dfs3(int x,int las){
	if(las)ans[x]=min(ans[x],ans[las]+1);
	for(int i=0;i<to[x].size();++i){
		int y=to[x][i];
		if(y==las)continue;
		dfs3(y,x);
	}
}
int main(){
	int n=read();
	e[0]=1;
	for(int i=1;i<=19;++i)e[i]=e[i-1]<<1;
	for(int i=2;i<=n;++i){
		int x=read();
		to[x].push_back(i);to[i].push_back(x);
	}
	dep[1]=1;
	dfs(1,0);
	memset(ans,0x3f,sizeof(ans));
	for(int i=1;i<=19;++i){
		for(int j=1;j<=qt-e[i]+1;++j){
			f[j][i]=(dep[f[j][i-1]]<dep[f[j+e[i-1]][i-1]])?f[j][i-1]:f[j+e[i-1]][i-1];
		}
	}
	int q=read();
	while(q--){
		int k=read();
		int u=0,v=0,len=0;
		while(k--){
			int x=read();
			if(u==0||v==0){
				if(u==0)u=x;
				else v=x;
				if(u&&v)len=calc(u,v);
				continue;
			}
			int lenu=calc(u,x),lenv=calc(v,x);
			if(lenu<lenv)swap(lenu,lenv),swap(u,v);
			if(lenu>len)v=x,len=lenu;
		}
		if(dep[u]<dep[v])swap(u,v);
		int z=tow(u,dep[u]-(len>>1));
		ans[z]=min(ans[z],(len>>1)+(len&1));
		if(len&1){
			ans[tt[z][0]]=min(ans[tt[z][0]],(len>>1)+(len&1));
		}
	}
	dfs2(1,0);
	dfs3(1,0);
	for(int i=1;i<=n;++i)ot(ans[i]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值