1. 程式人生 > >樹形結構練習總結

樹形結構練習總結

  • 這是我平生第一次在一天之內做完了一套vjudge上的練習~~(實際上是因為太簡單了,大佬根本都不屑於去做)~~
  • 雖然做完了,感覺問題還是很大。在想演算法的時候我總是不相信自己的判斷,一定要等看到正解思路和我差不多才敢打,或者有的時候要看到了題解的大致方向才能YY出方法。具體體現為:第一題明明想出了AC方法,卻以為自己想了個暴力;後面有的題又總是以為自己想的太簡單了;還有看了別人的思路才會做的F題。
  • 做難題還是不夠熟練,需要多多努力

A (CF686D)

After the piece of a devilish mirror hit the Kay’s eye, he is no longer interested in the beauty of the roses. Now he likes to watch snowflakes.

Once upon a time, he found a huge snowflake that has a form of the tree (connected acyclic graph) consisting of n nodes. The root of tree has index 1. Kay is very interested in the structure of this tree.

After doing some research he formed qq queries he is interested in. The ii-th query asks to find a centroid of the subtree of the node v

iv_i. Your goal is to answer all queries.

Subtree of a node is a part of tree consisting of this node and all it’s descendants (direct or not). In other words, subtree of node v is formed by nodes uu, such that node vv is present on the path from u to root.

Centroid of a tree (or a subtree) is a node, such that if we erase it from the tree, the maximum size of the connected component will be at least two times smaller than the size of the initial tree (or a subtree).

Input
The first line of the input contains two integers nn and qq (2 ≤ nn ≤ 300 000, 1 ≤ qq ≤ 300 000) — the size of the initial tree and the number of queries respectively.

The second line contains n1n - 1 integer p2p2, p3p3, \cdots, pnpn (1 ≤ pipi ≤ nn) — the indices of the parents of the nodes from 2 to n. Node 1 is a root of the tree. It’s guaranteed that pi define a correct tree.

Each of the following q lines contain a single integer viv_i (1 ≤ viv_i ≤ nn) — the index of the node, that define the subtree, for which we want to find a centroid.

Output
For each query print the index of a centroid of the corresponding subtree. If there are many suitable nodes, print any of them. It’s guaranteed, that each subtree has at least one centroid.

Example
Input
7 4
1 1 3 3 5 3
1
2
3
5
Output
3
2
3
6
就放英文題目了。讀題還是很重要的,有英語題目要多讀讀。
題意:

  • 給一棵樹,求若干棵子樹的重心。

思路:

  • 求重心的方法挺簡單的,對每一個節點uu,記錄一個fa[u]fa[u]表示父親,一個maxsub[u]maxsub[u]表示uu的子樹大小的最大值,一個sz[u]sz[u]表示uuuu為根的子樹大小,然後ctr[u]ctr[u]表示重心座標。
  • 求一棵樹的重心挺方便的,主要問題是求多顆。於是可以想從兒子的重心去推父親的重心,從而減小複雜度。我們可以把從某棵子樹推到父親為根的樹看做在那棵子樹的根上連上了另一棵樹,於是當前子樹的重心必定是向根的方向移動的。所以在更新一個節點uu時,可以用他兒子子樹的重心向上爬,一直到某個兒子的重心爬到了符合要求的地方,那個節點就是uu的重心。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int N = 3e5+10;
int n, q, fa[N];
vector<int> to[N];
int sz[N], maxsub[N], ctr[N];

void DFS(int u)
{
	maxsub[u] = 0;
	sz[u] = 1;
	if ((u == 1 && to[u].size() == 0) || (u != 1 && to[u].size() == 1)){
		ctr[u] = u;
		return;
	}
	for (int i = 0; i < to[u].size(); i++){
		int v = to[u][i];
		if (v == fa[u]) continue;
		DFS(v);
		sz[u] += sz[v];
		maxsub[u] = max(maxsub[u], sz[v]);
	}
	for (int i = 0; i < to[u].size(); i++){
		int v = to[u][i];
		if (v == fa[u]) continue;
		int now = ctr[v];
		bool fl = 0;
		while (1){//往上爬
			if (max(maxsub[now], sz[u]-sz[now]) <= sz[u]/2){
				fl = 1;
				break;
			}
			if (now == u) break;
			now = fa[now];
		}
		if (fl){
			ctr[u] = now;
			break;
		}
	}
}

int main()
{
	scanf("%d%d", &n, &q);
	for (int i = 2; i <= n; i++){
		scanf("%d", &fa[i]);
		to[i].push_back(fa[i]);
		to[fa[i]].push_back(i);
	}
	DFS(1);
	while (q--){
		int x;
		scanf("%d", &x);
		printf("%d\n", ctr[x]);
	}
	return 0;
}

B (CF191C)

They say that Berland has exactly two problems, fools and roads. Besides, Berland has n cities, populated by the fools and connected by the roads. All Berland roads are bidirectional. As there are many fools in Berland, between each pair of cities there is a path (or else the fools would get upset). Also, between each pair of cities there is no more than one simple path (or else the fools would get lost).

But that is not the end of Berland’s special features. In this country fools sometimes visit each other and thus spoil the roads. The fools aren’t very smart, so they always use only the simple paths.

A simple path is the path which goes through every Berland city not more than once.

The Berland government knows the paths which the fools use. Help the government count for each road, how many distinct fools can go on it.

Note how the fools’ paths are given in the input.

Input
The first line contains a single integer n (2 ≤ n ≤ 10510^5) — the number of cities.

Each of the next n - 1 lines contains two space-separated integers ui, vi (1 ≤ ui, vi ≤ n, ui ≠ vi), that means that there is a road connecting cities ui and vi.

The next line contains integer k (0 ≤ k ≤ 10510^5) — the number of pairs of fools who visit each other.

Next k lines contain two space-separated numbers. The i-th line (i > 0) contains numbers ai, bi (1 ≤ ai, bi ≤ n). That means that the fool number 2i - 1 lives in city ai and visits the fool number 2i, who lives in city bi. The given pairs describe simple paths, because between every pair of cities there is only one simple path.

Output
Print n - 1 integer. The integers should be separated by spaces. The i-th number should equal the number of fools who can go on the i-th road. The roads are numbered starting from one in the order, in which they occur in the input.

Examples
Input
5
1 2
1 3
2 4
2 5
2
1 4
3 5
Output
2 1 1 1
Input
5
3 4
4 5
1 4
2 4
3
2 3
1 3
3 5
Output
3 1 1 1
全果樹上差分+LCA,唯一一道打的超級自信的題,洛谷上也有好多類似的題(P3258)
就放個題留個紀念~~(拒絕放程式碼)~~

C(CF842C)

Ilya is very fond of graphs, especially trees. During his last trip to the forest Ilya found a very interesting tree rooted at vertex 1. There is an integer number written on each vertex of the tree; the number written on vertex i is equal to ai.

Ilya believes that the beauty of the vertex x is the greatest common divisor of all numbers written on the vertices on the path from the root to x, including this vertex itself. In addition, Ilya can change the number in one arbitrary vertex to 0 or leave all vertices unchanged. Now for each vertex Ilya wants to know the maximum possible beauty it can have.

For each vertex the answer must be considered independently.

The beauty of the root equals to number written on it.

Input
First line contains one integer number n — the number of vertices in tree (1 ≤ n ≤ 2·105).

Next line contains n integer numbers ai (1 ≤ i ≤ n, 1 ≤ ai ≤ 2·105).

Each of next n - 1 lines contains two integer numbers x and y (1 ≤ x, y ≤ n, x ≠ y), which means that there is an edge (x, y) in the tree.

Output
Output n numbers separated by spaces, where i-th number equals to maximum possible beauty of vertex i.

Examples
Input
2
6 2
1 2
Output
6 6
Input
3
6 2 3
1 2
1 3
Output
6 6 6
Input
1
10
Output
10
題意:

  • 求每個節點到根的路徑上所有數的GCD,可以在這條路上把一個點變成0,求最大GCD。

思路:

  • 比較暴力的:每個節點開一個set,記錄若去掉一個數根到當前點的所有可能的GCD,然後一個f[]f[]陣列記錄不變一個點的GCD。於是每個點的狀態可以從父節點轉移過來,有三種選擇:
  1. 把自己變成0,則把父節點f值和自己的值取GCD塞進set
  2. 自己不變0,到根的那條鏈上取一個數變0,則把父節點的set裡每個數取GCD塞進set裡
  3. 自己不變0,到根的那條鏈上也沒有一個數變0,f[v] = GCD(f[u] , a[v])
  • 好像我也不知道最後set裡存了多少數,反正不會很多就對了。。。

  • 還有一個O(nn)O(n\sqrt{n})的方法。用一個sum[i]陣列存當前鏈上有因數i的節點數量,在進入節點的時候++,回溯的時候 --。然後如果有一個因子出現了depth-1次,他就是可以作為當前點的GCD的,取這些可行的數裡面最大的就是這個點的答案了。

//用set的打法,後面那種沒有試過,網上看來貌似是對的吧
//set真提莫好用
#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#include<vector>
using namespace std;
const int N = 2e5+10;
int n, a[N], dp[N];
vector<int> to[N];
set<int> s[N];

int GCD(int x, int y)
{
	if (y == 0) return x;
	return GCD(y, x%y);
}

void DFS(int u, int fa)
{
	for (int i = 0; i < to[u].size(); i++){
		int v = to[u][i];
		if (v == fa) continue;
		dp[v] = GCD(dp[u], a[v]);
		s[v].insert(dp[u]);//set的插入
		for (set<int>::iterator i = s[u].begin(); i != s[u].end(); i++)//set的遍歷
			s[v].insert(GCD(a[v], *i));
		DFS(v, u);
	}
}

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	for (int i = 1; i < n; i++){
		int x, y;
		scanf("%d%d", &x, &y);
		to[x].push_back(y);
		to[y].push_back(x);
	}
	dp[1] = a[1];
	s[1].insert(0);
	s[1].insert(a[1]);
	DFS(1, 0);
	for (int i = 1; i <= n; i++)
		printf("%d ", *s[i].rbegin());//set的反向第一個元素(就是最後一個),還是保證排好序的,也就是最大的
	return 0;
}

D(CF813C)

Alice got tired of playing the tag game by the usual rules so she offered Bob a little modification to it. Now the game should be played on an undirected rooted tree of n vertices. Vertex 1 is the root of the tree.

Alice starts at vertex 1 and Bob starts at vertex x (x ≠ 1). The moves are made in turns, Bob goes first. In one move one can either stay at the current vertex or travel to the neighbouring one.

The game ends when Alice goes to the same vertex where Bob is standing. Alice wants to minimize the total number of moves and Bob wants to maximize it.

You should write a program which will determine how many moves will the game last.

Input
The first line contains two integer numbers n and x (2 ≤ n ≤ 2·105, 2 ≤ x ≤ n).

Each of the next n - 1 lines contains two integer numbers a and b (1 ≤ a, b ≤ n) — edges of the tree. It is guaranteed that the edges form a valid tree.

Output
Print the total number of moves Alice and Bob will make.

Examples
Input
4 3
1 2
2 3
2 4
Output
4
Input
5 2
1 2
2 3
3 4
2 5
Output
6
Note
In the first example the tree looks like this:
這裡寫圖片描述

The red vertex is Alice’s starting position, the blue one is Bob’s. Bob will make the game run the longest by standing at the vertex 3 during all the game. So here are the moves:

B: stay at vertex 3

A: go to vertex 2

B: stay at vertex 3

A: go to vertex 3

In the second example the tree looks like this:
這裡寫圖片描述

The moves in the optimal strategy are:

B: go to vertex 3

A: go to vertex 2

B: go to vertex 4

A: go to vertex 3

B: stay at vertex 4

A: go to vertex 4
博弈的題,兩遍遍歷,分別搞出alice和bob到每個點的距離,如果alice到某個點的距離大於(不能等於)bob的,那bob就可以跑到這裡避難(至於等於,bob不走這一步比走這一步要更優,而且等於可能出現路徑的重複,那bob在還沒走到之前就被抓了)。於是讓bob挑一個可行的避難點裡alice走的路最長的就好了。

E

Alyona decided to go on a diet and went to the forest to get some apples. There she unexpectedly found a magic rooted tree with root in the vertex 1, every vertex and every edge of which has a number written on.

The girl noticed that some of the tree’s vertices are sad, so she decided to play with them. Let’s call vertex v sad if there is a vertex u in subtree of vertex v such that dist(v, u) > au, where au is the number written on vertex u, dist(v, u) is the sum of the numbers written on the edges on the path from v to u.

Leaves of a tree are vertices connected to a single vertex by a single edge, but the root of a tree is a leaf if and only if the tree consists of a single vertex — root.

Thus Alyona decided to remove some of tree leaves until there will be no any sad vertex left in the tree. What is the minimum number of leaves Alyona needs to remove?

Input
In the first line of the input integer n (1 ≤ n ≤ 10510^5) is given — the number of vertices in the tree.

In the second line the sequence of n integers a1, a2, …, an (1 ≤ ai ≤ 10910^9) is given, where ai is the number written on vertex i.

The next n - 1 lines describe tree edges: ith of them consists of two integers pi and ci (1 ≤ pi ≤ n,  - 10910^9 ≤ ci ≤ 10910^9), meaning that there is an edge connecting vertices i + 1 and pi with number ci written on it.

Output
Print the only integer — the minimum number of leaves Alyona needs to remove such that there will be no any sad vertex left in the tree.

Example
Input
9
88 22 83 14 95 91 98 53 11
3 24
7 -8
1 67
1 64
9 65
5 12
6 -80
3 8
Output
5
Note
The following image represents possible process of removing leaves from the tree:
這裡寫圖片描述

題意:去掉一些葉子(去掉之後成為葉子也可以去),使得對於每一個v和他的子樹中的u,dist(v, u) <= a[u]
思路:記錄從當前點出發往根的方向走的路徑中權值最大的那條(不一定連到根),每一次只要路徑權值大於a[u],就把這整棵子樹去掉,一遍dfs搞定

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
using namespace std;
const int N = 1e5+10;
int n, a[N], s[N];
vector<int> to[N];
vector<int> val[N];
bool col[N];

void DFS(int u, int fa)
{
	col[u] = 1;
	for (int i = 0; i < to[u].size(); i++){
		int v = to[u][i];
		int w = val[u][i];
		if (v == fa) continue;
		s[v] = max(w, s[u]+w);
		if (s[v] > a[v]) continue;
		DFS(v, u);
	}
}

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	for (int i = 2; i <= n; i++){
		int x, c;
		scanf(