---
# System prepended metadata

title: DSA-HW4-NonProgrammingPart

---

# DSA-HW4-NonProgrammingPart
## B07902060 資工一 趙雋同
### Problem 1. k-th Largest Element
#### 1.

```clike=
typedef struct RBtree{
	int color;
	int value;
	int descendants;
	struct RBtree *left , *right , *parent;
}rb;
int sz(rb *root){
	if(root == NULL)
		return 0;
	root->descendants = sz(root->left) + sz(root->right) + 1;
	return root->descendants;
}
```
利用遞迴遍歷整棵RB tree，如果root是NIL的話，就return 0代表該節點沒有子孫，若不是NIL的話，即為其左右子孫的descendants的數量加上自己（+1）。由於每個節點只會走到一次，所以time-complexity是O(n).

#### 2.
由於需要變動的sz(x)只有插入時被訪問到的節點，且紅黑數的高度為$O(logn)$，那麼調整sz(x)的time-complexity為$O(logn)$，而因為紅黑樹本身的插入也為$O(logn)$，所以整體需要$O(logn)$的時間。
#### 3. 
跟第二小題差不多的概念，我們只要更新訪問過的節點就好，從root開始，直到找到要刪除的節點，我令所有訪問過的節點的sz(x)皆減一，之後在找predecesor或是successor時，也令所有訪問過得節點的sz(x)減一，再讓predecesor(or succesor)移到要刪除的節點後並將它的sz value等於刪除的節點的sz value-1，而因為紅黑樹的高度為$O(logn)$，所以刪除以及調整sz(x)的time-complexity為$O(logn)$
#### 4.
假設要執行left-rotate(X)，且X的left-child為A而right-child為Y，Y又有其left-child B和right-child C 。於是我們可以知道在rotate前:

$sz(X)=sz(A)+sz(Y)+1=sz(A)+sz(B)+sz(C)+2$
$sz(Y)=sz(B)+sz(C)+1$

而因為node A,B,C他們在rotate之後children不變，所以$sz(A),sz(B),sz(C)$維持不變，而X的ancestor的children總數不變，所以只要考慮$sz(X)$以及$sz(Y)$的變化，而我們知道rotate之後:

$sz(X)=sz(A)+sz(B)+1$
$sz(Y)=sz(X)+sz(C)+1=sz(A)+sz(B)+sz(C)+2$

```clike=
rotate-sz(x)
	a = sz(x.left)
	c = sz(y.left)
	tmp1 = sz(x)
	tmp2 = sz(y)
	sz(x) = tmp2-c+a
	sz(y) = tmp1
```

可以看出rotate-sz(x)的time-complexity是 $O(1)$
#### 5 
```clike=
int find_kth_largest(rb *root ,int k){
    if(k == sz(root->right)+1 )
	return root->value;
    else if (k <= sz(root->right) )
	return find_kth_largest(root->right , k);
    else
	return find_kth_largest(root->left , k-sz(root->right)-1 );
}
```

分成三種情況：
***(a)*** : 依照RB tree的建構規則，root的左子孫皆小於他；右子孫皆大於他，所以如果k等於sz(root->right)+1的話，root就是該子樹k'th largest element
***(b)*** : 假如k小於等於sz(root->right)的話，就代表我們要尋找的在右子樹中，由於右小孩皆大於root，所以我們找的還是右子樹裡的k'th largest element,以遞迴帶入。
***\(c\)*** : 如果k大於sz(root->right)+1的話，代表k'th largest element 在左子樹中，由於root跟root的右小孩全大於root的左小孩，所以我們改為尋找左子樹中(k-sz(root->right)-1)'th largest element，同樣以遞迴帶入。

-----------

### Problem 2. Strongly Connected Component
#### 1 
![](https://i.imgur.com/FchpQF2.png)

#### 2
strongly connected component在reverve後依舊是strongly connected,那麼能夠reduce的點集合先reverese再reduce跟先reduce再reverse會是一樣的結果。

#### 3
```clike=
#include<stdio.h>
#include<stdlib.h>
#define MAXN 100
#define Slen 1000
typedef struct Edge{
	int index;
	struct Edge *next;
}edge;
typedef struct Vertex{
	edge *next;
	int color;
	int pi;
	int d;
	int f;
}vertex;
int N;
vertex V[MAXN];
vertex reversingV[MAXN];
int ts;
int Stack[Slen] = {0};
int ptr = -1;
int gr = 1;
int SSC[MAXN];
void Push(int data){
	Stack[++ptr] = data;
}
int Pop(){
	return Stack[ptr--];
}
void DFS_visit(int u){
	++ts;
	V[u].d = ts;
	V[u].color = 1;
	edge *next = V[u].next;
	while(next != NULL){
		if(V[next->index].color == 0){
			V[next->index].pi = u;
			DFS_visit(next->index);
		}
		next = next->next;
	}
	V[u].color = 2;
	++ts;
	V[u].f = ts;
	Push(u);
}
void DFS(){
	for(int i=0;i<N;i++){
		V[i].color = 0;
		V[i].pi = -1;
	}
	ts = 0;
	for(int i=0;i<N;i++)
		if(V[i].color == 0)
			DFS_visit(i);
}
void build_edge(vertex cur[] , int x ,int y){
	edge *new = (edge*)malloc(sizeof(edge));
	new->index = y;
	new->next = cur[x].next;
	cur[x].next = new;
}
void reverse_DFS_visit(int u){
	++ts;
	reversingV[u].d = ts;
	reversingV[u].color = 1;
	edge *next = reversingV[u].next;
	while(next != NULL){
		if(reversingV[next->index].color == 0){
			SSC[next->index] = gr;
			reversingV[next->index].pi = u;
			reverse_DFS_visit(next->index);
		}
		next = next->next;
	}
	reversingV[u].color = 2;
	++ts;
	reversingV[u].f = ts;
}
void find_SSC(){
	int v;
	ts = 0;
	for(int i=0;i<N;i++){
		reversingV[i].color = 0;
		reversingV[i].pi = -1;
	}
	while(ptr != -1){
		v = Pop();
		//printf("%d\n",v);
		if(reversingV[v].color == 0){
			SSC[v] = gr;
			reverse_DFS_visit(v);
			gr++;
		}
	}
}
int main(){
	int edge_N;
	int x,y;
	scanf("%d%d",&N,&edge_N);
	for(int i=0;i<edge_N;i++){
		scanf("%d%d",&x,&y);
		build_edge(V,x,y);
		build_edge(reversingV,y,x);
	}
	DFS();
	//printf("%d\n",ptr);
	find_SSC();
	for(int i=0;i<N;i++)
		printf("%d'th vertex is in group %d\n",i,SSC[i]);
	return 0;
}
```
在V & reversingV 的build_edge中的time-complexity是 $O(E)$
DFS的方面time-complexity $O(V+E)$
find_SSC的方面只是作reversingV 的DFS，所以也是 $O(V+E)$
print SSC的部份是 $O(V)$
所以整個code的time-complexity就是 $O(V+E)$
