[ICPC 2024 Hangzhou R] Heavy-light Decomposition

time limit per test

1 second

memory limit per test

1024 megabytes

Heavy-light Decomposition (HLD) is a useful technique applied to trees for efficiently querying chains of vertices. Let's first review the definition of HLD in case you forget.

You are given a rooted tree with n vertices, numbered from 1 to n. You need to classify each non-root vertex as either heavy or light. Each non-leaf vertex has exactly one child classified as heavy, and the remaining vertices as light.

For any non-root vertex v, let u be its parent. Vertex v can be classified as heavy only if the size of its subtree is among the largest of all the children of u. More formally, denote the size of the subtree rooted at vertex v as sv, and let ch(u) represent the set of children of u. Then, v can be heavy only if sv≥sw for all w∈ch(u). Note that there might be several children of u satisfying this constraint; in this case, you should choose one of them to be heavy, and the others to be light.

After that, all vertices of the tree can be decomposed into several non-overlapping heavy chains, where each vertex belongs to exactly one heavy chain. A heavy chain is a sequence of vertices x1,x2,…,xk satisfying all the following constraints.

  • x1 is either the root or a light vertex.
  • For all 2≤i≤k, xi is xi−1's child and is a heavy vertex.
  • xk is a leaf.

An HLD example. Heavy chains are marked with solid red edges.

For example, the above figure shows a valid HLD of the given tree with 12 vertices, where the heavy chains are [1,2,3,4,5], [9,10,11], [7,8], [6], and [12].

Pig100Ton is a very experienced competitive programming contestant in Pigeland. He wants to know whether it is possible to recover the original tree from the heavy chains after HLD. Specifically, he will give you the number of vertices n of the original tree and k heavy chains. The i-th chain is described by two integers li and ri, indicating a heavy chain li,li+1,…,ri.

Your task is to construct a tree satisfying the following constraints or to tell Pig100Ton it is impossible:

  • It is a rooted tree that contains n vertices numbered from 1 to n.
  • The k chains provided by Pig100Ton should form a valid HLD of the tree. A valid HLD refers to a valid way to classify each non-root vertex as either light or heavy, and then decompose the tree into several non-overlapping heavy chains.

有道 翻译

重-轻分解(HLD)是一种应用于树的有用技术,可以有效地查询顶点链。让我们首先回顾一下HLD的定义,以免您忘记。

给定一个有 n 个顶点的有根树,编号从 1 到 n 。您需要将每个非根顶点分类为重顶点或轻顶点。每个非叶顶点都有一个被分类为重的子顶点,其余的被分类为轻顶点。

对于任何非根顶点 v ,设 u 为它的父顶点。只有当顶点 v 的子树的大小在 u 的所有子树中最大时,顶点 v 才能被归类为重顶点。更正式地说,表示以顶点 v 为根的子树的大小为 sv ,并让 ch(u) 表示 u 的子树集合。那么,只有当 sv≥sw 对于所有 w∈ch(u) 来说, v 才是重的。注意可能有几个 u 的子元素满足这个约束;在这种情况下,你应该选择其中一个是重的,而其他是轻的。

之后,树的所有顶点都可以分解成几个不重叠的重链,其中每个顶点恰好属于一个重链。一个重链是一个满足以下所有约束的顶点序列 x1,x2,…,xk 。

  • x1 是根或光顶点。

-对于所有 2≤i≤k , xi 是 xi−1 的子顶点,是一个重顶点。

— xk 是一个叶子。

! [] (https://espresso.codeforces.com/220953e5240cbcce77bca067b5cb080d99900032.png)

一个HLD的例子。沉重的铁链上有坚实的红色边缘。

例如,上图显示了具有 12 顶点的给定树的有效HLD,其中重链为 [1,2,3,4,5] , [9,10,11] , [7,8] , [6] 和 [12] 。

Pig100Ton是Pigeland非常有经验的竞技编程选手。他想知道HLD后是否有可能从重链中恢复原来的树。具体来说,他会给你原始树的 n 和 k 重链的顶点数。第 i 条链由两个整数 li 和 ri 描述,表示一条重链 li,li+1,…,ri 。

你的任务是构造一棵满足以下约束条件的树,或者告诉Pig100Ton这是不可能的:

—是一个有根的树,包含 n 个顶点,编号从 1 到 n 。

  • Pig100Ton提供的 k 链应构成该树的有效HLD。一个有效的HLD指的是一种有效的方法,将每个非根顶点分类为轻或重,然后将树分解为几个不重叠的重链。

Input

There are multiple test cases. The first line of the input contains an integer T (1≤T≤105) indicating the number of test cases. For each test case:

The first line contains two integers n and k (1≤n≤105, 1≤k≤n), indicating the number of vertices of the tree and the number of heavy chains after its HLD.

For the following k lines, the i-th line contains two integers li and ri (1≤li≤ri≤n), indicating that the i-th heavy chain is li,li+1,…,ri.

It is guaranteed that each of the n vertices belongs to exactly one given heavy chain. It is also guaranteed that the sum of n of all test cases does not exceed 2×105.

有道 翻译

输入** **

有多个测试用例。输入的第一行包含一个整数 T ( 1≤T≤105 ),表示测试用例的数量。对于每个测试用例:

第一行包含两个整数 n 和 k ( 1≤n≤105 , 1≤k≤n ),表示树的顶点数和HLD后的重链数。

对于接下来的 k 行, i \第一行包含两个整数 li 和 ri ( 1≤li≤ri≤n ),表明 i \第一个重链是 li,li+1,…,ri 。

它保证每个 n 顶点都属于一个给定的重链。同时保证所有测试用例的 n 之和不超过 2×105 。

Output

For each test case:

If it is possible to construct such a tree, output one line containing n integers p1,p2,⋯,pn separated by a space, where pi is the parent of vertex i. pi=0 indicates that vertex i is the root. If there are multiple valid solutions, you may output any one of them.

If it is not possible to construct such a tree, just output IMPOSSIBLE in one line.

有道 翻译

** **输出

对于每个测试用例:

如果可以构造这样的树,输出一行包含 n 个整数 p1,p2,⋯,pn ,中间用空格分隔,其中 pi 是顶点 i 的父结点。 pi=0 表示顶点 i 是根节点。如果有多个有效的解,您可以输出其中的任何一个。

如果不可能构建这样的树,只需在一行中输出IMPOSSIBLE。

Example

Input

Copy



3

12 5

1 5

9 11

7 8

6 6

12 12

4 3

1 1

4 4

2 3

2 2

1 1

2 2

Output

Copy

0 1 2 3 4 3 2 7 1 9 10 10
2 0 2 2
IMPOSSIBLE

Note

For the first test case, the sample output is the tree shown in the description.

有道 翻译

注意

对于第一个测试用例,示例输出是描述中显示的树。

思路

构造+贪心。

代码见下

#include<bits/stdc++.h>
using namespace std;
long long t,n,k,l[100005],r[100005],lma=0,lmi=1e18+7,sxs,ua=0,f[100005];
int main(){
	cin>>t;
	while(t--){
		cin>>n>>k;
		lma=0;
		lmi=1e18+7;
		sxs=1;
		ua=0;
		for(int i=1;i<=k;i++){
			cin>>l[i]>>r[i];
			if(r[i]-l[i]+1==lma){
				sxs++;
			}
			else if(r[i]-l[i]+1>=lma+1){
				lma=r[i]-l[i]+1;
				sxs=1;
				ua=l[i];
			}
			if(r[i]-l[i]+1<=lmi-1){
				lmi=r[i]-l[i]+1;
			}			
		}
		if(k==1){
			for(int i=1;i<=n;i++){
				cout<<i-1<<" ";
			}
			cout<<endl;
		}
		else if(lma==lmi||(lmi+1==lma&&sxs>=2)){
			cout<<"IMPOSSIBLE"<<endl;
		}
		else{
			if(sxs==1){
				for(int i=1;i<=k;i++){
					if(l[i]==ua){
						f[l[i]]=0;
					}
					else{
						f[l[i]]=ua;
					}
					for(int j=l[i]+1;j<=r[i];j++){
						f[j]=j-1;
					}
				}				
				for(int i=1;i<=n;i++){
					cout<<f[i]<<" ";
				}
				cout<<endl;
			}
			else{
				for(int i=1;i<=k;i++){
					if(l[i]==ua){
						f[l[i]]=0;
					}
					else if(r[i]-l[i]+1!=lmi){
						f[l[i]]=ua;
					}
					else{
						f[l[i]]=ua+1;
					}
					for(int j=l[i]+1;j<=r[i];j++){
						f[j]=j-1;
					}
				}				
				for(int i=1;i<=n;i++){
					cout<<f[i]<<" ";
				}
				cout<<endl;				
			}
		}
	}
	return 0;
}

posted @ 2025-10-11 18:25  bz02_2023f2  阅读(20)  评论(0)    收藏  举报  来源