[USACO22JAN] Tests for Haybales G

洛谷[USACO22JAN] Tests for Haybales G

题目大意

你要选定一个数 k k k并构造一个数组 x i x_i xi,满足 x 1 ≤ x 2 ≤ ⋯ ≤ x n x_1\leq x_2\leq \cdots\leq x_n x1x2xn,且对于每一个 i i i,都满足 j i j_i ji为使得 x j i ≤ x i + k x_{j_i}\leq x_i+k xjixi+k的最大的位置。给出 j i j_i ji,并满足 i ≤ j i i\leq j_i iji以及 j 1 ≤ j 2 ≤ ⋯ ≤ j n ≤ n j_1\leq j_2\leq \cdots\leq j_n\leq n j1j2jnn

输出 k k k和数组 x i x_i xi,需满足 1 ≤ k ≤ 1 0 18 1\leq k\leq 10^{18} 1k1018 0 ≤ x i ≤ 1 0 18 0\leq x_i\leq 10^{18} 0xi1018

1 ≤ n ≤ 1 0 5 1\leq n\leq 10^5 1n105


题解

首先,我们可以将 j i j_i ji都加上 1 1 1,那其意义就变为了第一个大于 x i + k x_i+k xi+k的位置。

建一棵 n + 1 n+1 n+1个节点的数,对于每个节点 i i i,以 j i + 1 j_i+1 ji+1作为父亲并连一条边,那么根节点就为 n + 1 n+1 n+1

对于每一层,我们需要这一层的节点比它的每一个儿子的值大 k k k以上。那么,我们可以将深度为 d e p dep dep的点的 x x x值定为 ( n + 1 − d e p ) × k + t ( 0 ≤ t < k ) (n+1-dep)\times k+t(0\leq t (n+1dep)×k+t(0t<k)

t t t需要满足:

  • 点的深度越大, t t t越小
  • 点的标号越大, t t t越大

我们发现, d f s dfs dfs序与这个条件正好相反。那么,我们令 t = k − d f n i t=k-dfn_i t=kdfni。因为连边时是从小到大,所以遍历时是从大到小,编号越大, d f n i dfn_i dfni就越小, k − d f n i k-dfn_i kdfni就越大。

需要满足 k > n k>n k>n,还要注意 x i x_i xi的范围。

时间复杂度为 O ( n ) O(n) O(n)

code

#include
using namespace std;
int n,x,tot=0,dfn=0,d[200005],l[200005],r[200005];
long long k=1e6,v[200005],ans[200005];
void add(int xx,int yy){
	l[++tot]=r[xx];d[tot]=yy;r[xx]=tot;
}
void dfs(int u){
	ans[u]=v[u]*k-(++dfn);
	for(int i=r[u];i;i=l[i]){
		v[d[i]]=v[u]-1;
		dfs(d[i]);
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&x);
		add(x+1,i);
	}
	v[n+1]=n+1;dfs(n+1);
	printf("%lld\n",k);
	for(int i=1;i<=n;i++){
		printf("%lld\n",ans[i]);
	}
	return 0;
}

你可能感兴趣的:(题解,题解)