Tree - GitDeveloperKim/DreamEach GitHub Wiki

ํŠธ๋ฆฌ (Tree)

  • ํŠธ๋ฆฌ๋ž€ ๋…ธ๋“œ N๊ฐœ์™€ ๊ฐ„์„  N-1๊ฐœ๋กœ ์ด๋ฃจ์–ด์ง„ ์‚ฌ์ดํด ์—†๋Š” ์—ฐ๊ฒฐ ๊ทธ๋ž˜ํ”„๋ฅผ ๋งํ•œ๋‹ค
  • ๋ฃจํŠธ ๋…ธ๋“œ : ๋ถ€๋ชจ๊ฐ€ ์—†๋Š” ์ตœ์ƒ์œ„ ๋…ธ๋“œ
  • ๋‹จ๋ง ๋…ธ๋“œ : ์ž์‹์ด ์—†๋Š” ๋…ธ๋“œ
  • ํฌ๊ธฐ : ํŠธ๋ฆฌ์— ํฌํ•จ๋œ ๋ชจ๋“  ๋…ธ๋“œ์˜ ๊ฐœ์ˆ˜
  • ๊นŠ์ด : ๋ฃจํŠธ ๋…ธ๋“œ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ
  • ๋†’์ด : ๊นŠ์ด ์ค‘ ์ตœ๋Œ€๊ฐ’
  • ์ฐจ์ˆ˜ : ๊ฐ ๋…ธ๋“œ์˜ ๊ฐ„์„  ๊ฐœ์ˆ˜

์ด์ง„ํŠธ๋ฆฌ (Binary Search Tree)

  • ๋ถ€๋ชจ๋…ธ๋“œ : N
  • ์ž์‹ ๋…ธ๋“œ : Nx2, Nx2+1
  • ์ž์‹ ๋…ธ๋“œ -> ๋ถ€๋ชจ๋…ธ๋“œ : N/2
  • ํ•„์š”ํ•œ ๋…ธ๋“œ์˜ ๊ฐœ์ˆ˜ 2^(h+1) +1 or ๋ณดํ†ต 4*N์ด๋ฉด ์ปค๋ฒ„ ๊ฐ€๋Šฅ (์ข…๋งŒ๋ถ)
  • ํŠธ๋ฆฌ์˜ ๋†’์ด logN
  • ๋ฌธ์ œํ’€์ด

ํŠธ๋ฆฌ์˜ ์ง€๋ฆ„

  • ํŠธ๋ฆฌ์˜ ์ง€๋ฆ„์€ ๋‘ ๋…ธ๋“œ ๊ฐ„ ๊ฒฝ๋กœ์˜ ๊ธธ์ด ์ค‘ ์ตœ๋Œ“๊ฐ’์ด๋‹ค.
  • ์ฒซ๋ฒˆ์งธ ๋ฐฉ๋ฒ•, ์ž„์˜์˜ ๋…ธ๋“œ๋ฅผ ๋ฃจํŠธ๋กœ ์ง€์ •ํ•œ ๋‹ค์Œ ๊ฐ ์„œ๋ธŒํŠธ๋ฆฌ์— ๋Œ€ํ•ด ๋”ฐ๋กœ๋”ฐ๋กœ ๋ฌธ์ œ๋ฅผ ํ‘ผ๋‹ค
  • ๋‘๋ฒˆ์งธ ๋ฐฉ๋ฒ•, ๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰์„ ๋‘๋ฒˆ ์ง„ํ–‰
  • TBD

LCA (lowest Common Acestor)

  • ์ตœ์†Œ ๊ณตํ†ต ์กฐ์ƒ ๋ฌธ์ œ๋Š” ๋‘ ๋…ธ๋“œ์˜ ๊ณตํ†ต๋œ ์กฐ์ƒ ์ค‘์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์กฐ์ƒ์„ ์ฐพ๋Š” ๋ฌธ์ œ

ํ•„์š” ์ž๋ฃŒ๊ตฌ์กฐ

  • ArrayList : ์ž…๋ ฅ๊ฐ’ ์ •์ ๋“ค์˜ ์ •๋ณด
  • parent[] : ๋‚˜์˜ ๋ถ€๋ชจ ์ •์ 
  • depth[] : ๋‚˜์˜ ๊นŠ์ด
  • ๋ฃจํŠธ๋…ธ๋“œ(1)๊ฐ€ ์ •ํ•ด์ง€๋ฉด ๊ฐ ๋…ธ๋“œ์˜ Depth ๋ฅผ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ๋‹ค -> DFS ์ด์šฉ
  • ๋งค ์ฟผ๋ฆฌ๋งˆ๋‹ค ๋ถ€๋ชจ ๋ฐฉํ–ฅ์œผ๋กœ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๊ธฐ ์œ„ํ•ด ์ตœ์•…์˜ ๊ฒฝ์šฐ O(N)์˜ ์‹œ๊ฐ„ ๋ณต์žก๋„, ์ฆ‰ ๋ชจ๋“  ์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ ๋ณต์žก๋„ O(NM)
  • ๋ฐฑ์ค€ 3584

static int solve(int a, int a_depth, int b, int b_depth){
        // ๋‘˜์˜ depth๊ฐ€ ๊ฐ™์•„์งˆ ๋•Œ๊นŒ์ง€ ์œ„๋กœ ์˜ฌ๋ฆฐ๋‹ค.
        if(a_depth > b_depth){
            while(a_depth != b_depth){
                a_depth--;
                a = parent[a];
            }
        }
        else if(a_depth < b_depth){
            while(a_depth != b_depth){
                b_depth--;
                b = parent[b];
            }
        }

        // ๋‘˜์˜ ๋ถ€๋ชจ๊ฐ’์ด ๊ฐ™์•„์งˆ ๋•Œ๊นŒ์ง€ ์œ„๋กœ ์˜ฌ๋ฆฐ๋‹ค
        while(a != b){
            a = parent[a];
            b = parent[b];
        }

        return a;
    }

Sparse table + LCA (์„ฑ๋Šฅ ๊ฐœ์„ )

  • LCA ๋กœ์ง์—์„œ ๋ถ€๋ชจ๋ฅผ ๋ฐ”๋กœ์œ„ ํ•˜๋‚˜์”ฉ ๊ฒ€์ƒ‰ํ•˜์ง€ ์•Š๊ณ  2^i ์ง€์ˆ˜์Šน์œผ๋กœ ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ๋น„๊ต๋ฅผ ํ•˜๋ฉด ์†๋„๊ฐ€ ์ข‹์•„์ง„๋‹ค?
  • sparse table ํ™•์ธ ํ•„์š” click
  • Sparse Table ์—์„œ ์ ํ™”์‹ ์•”๊ธฐ: arr[i][j] = arr[ arr[i][j-1] ][j-1]
  • j ๊ฐ’์€ ์ด log2(๋…ธ๋“œ ์ˆ˜) ๋กœ ๊ณ„์‚ฐ
  • ์ด 15์นธ ์˜ฌ๋ผ๊ฐ€์•ผ ํ•œ๋‹ค๋ฉด (8์นธ -> 4์นธ -> 2์นธ -> 1์นธ)
  • ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์กฐ๊ธˆ ๋” ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ๋…ธ๋“œ์— ๋Œ€ํ•˜์—ฌ 2^i ๋ฒˆ ๋ถ€๋ชจ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ๊ธฐ๋ก / ์‹œ๊ฐ„๋ณต์žก๋„ O(MlogN)
  • ๋ฐฑ์ค€ 11438 lca2
 //find_depth(1,1) ๋ฃจํŠธ๊ฐ€ 1๋ฒˆ ๋…ธ๋“œ, ๊นŠ์ด 1
	public static void find_depth (int from, int depth) {
		d[from] = depth;
		
		for (int i = 0; i < mat[from].size(); i++) {
			int to = mat[from].get(i);
			if (d[to] == 0) {
				parent[to][0] = from; // ๊ธฐ์ € ๋ฐฐ์—ด ์ƒ์„ฑ
				find_depth(mat[from].get(i), depth+1);
			}
		}
	}

	public static void make_parent ( ) {
		for (int j = 1 ; j < k; j++) {  // j๋จผ์ €
			for (int i = 1; i<= N; i++) {  // i๋ฒˆ
				parent[i][j] = parent[ parent[i][j-1] ] [j-1];// ์ ํ™”์‹ ์ ์šฉ
			}
		}
	}

int find_lca(int a, int b) {
    if (depth[a] < depth[b]) { // a๊ฐ€ ๋” ๊นŠ์€ ๋…ธ๋“œ๊ฐ€ ๋˜๊ฒŒ
        int temp = a;
        a = b;
        b = temp;
    }

    // a์˜ depth๋ฅผ b์— ๋งž์ถ˜๋‹ค
    int diff = depth[a] - depth[b];
    int m = 0;

    // ์˜ˆ๋ฅผ ๋“ค์–ด 13๋งŒํผ ์˜ฌ๋ผ๊ฐ€์•ผ ํ•œ๋‹ค๋ฉด ์ด๊ฒƒ์„ ์ด์ง„์ˆ˜๋กœ ํ‘œํ˜„, 1101(2)์ด๋ฏ€๋กœ 
    // 1์ธ ๊ณณ์„ ํƒ์ƒ‰ํ•  ๋•Œ ๋งˆ๋‹ค sparse ํ…Œ์ด๋ธ”์˜ ๋†’์ด ๊ฐ’์„ ์ฆ๊ฐ€ ์‹œํ‚ค๋ฉด ๋œ๋‹ค
    while (diff) {
        if (diff & 1) {
            a = parent[a][m];
        }
        m++;
        diff /= 2;
    }

    int lca;

    // a์™€ b๊ฐ€ ๊ฐ™๋‹ค๋ฉด ๊ทธ๊ฒƒ์ด lca
    if (a == b) {
        lca = a;
    } else {
        for (int k = 15; k >= 0; k--) {
            if (parent[a][k] != parent[b][k]) {
                a = parent[a][k];
                b = parent[b][k];
            }
        }
        lca = parent[a][0];
    }

    return lca;
}

์ถœ์ฒ˜ click

์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ (Segment Tree)

  • ๋‹ค์ฐจ์› ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ
  • ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ with lazy propagation
  • ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ with dynamic
  • ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ with Persistent segment tree
  • bottom up ๊ตฌํ˜„
  • top down ๊ตฌํ˜„
  • ๋ฐฑ์ค€ ์ด๋ก  ์„ค๋ช… click

๋ฌธ์ œํ’€์ด ๋ฐฑ์ค€2042

์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์ƒ์„ฑ ์ˆ˜๋„์ฝ”๋“œ

  • ํŠธ๋ฆฌ์˜ ํฌ๊ธฐ๋ฅผ ๊ตฌํ•˜๋Š” ์›๋ฆฌ click

tree = new int [1 << (my_log(200_0000)+1)]; // 200_0000 ๋ฆฌํ”„๋…ธ๋“œ์˜ ์ตœ๋Œ€๊ฐฏ์ˆ˜

static long init (int node, int start, int end) {
	if (start == end) {
		// leaf node
		return tree[node] = array[start];
	} else {
		// not leaf node
		return tree[node] = init (node*2, start, (start+end)/2) + init (node*2+1, (start+end)/2+1, end);	// init left child node and right child node 
	}
}

๊ตฌ๊ฐ„ํ•ฉ ๊ตฌํ•˜๊ธฐ ์ˆ˜๋„์ฝ”๋“œ left right ๊ฐ€ ์ฐพ์•„์•ผ ํ•˜๋Š” ๊ตฌ๊ฐ„, start, end๊ฐ€ ํƒ์ƒ‰ ๊ตฌ๊ฐ„


static long sum (int node, int start, int end, int left, int right) {
	if (left > end || right < start) {
		return 0;
	} 
	if (left <= start && end <= right) {
		return tree[node];
	}
	return sum (node*2, start, (start+end)/2, left, right) + sum (node*2+1, (start+end)/2+1, end, left, right);		
}

์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ ์—…๋ฐ์ดํŠธ ์ˆ˜๋„์ฝ”๋“œ


static void update (int node, int start, int end, int index, long diff) {
	if (index < start || index > end) 
		return;
	tree[node] += diff;	
	if (start != end) {
		update (node*2, start, (start+end)/2, index, diff);
		update (node*2+1, (start+end)/2+1, end, index, diff);
	}
}

  • k๋ฒˆ์งธ ์ˆ˜ ์ฐพ๊ธฐ
    1. ์ „์ฒด ๊ฐ€์งˆ์ˆ˜ ์žˆ๋Š” ์ˆ˜๋ฅผ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ ๋ฐฐ์—ด๋กœ ๋งŒ๋“ฌ
    2. ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ์— ๋“ค์–ด์˜จ ํ•ด๋‹น ์ˆซ์ž์˜ ์ธ๋ฑ์Šค(๋ฆฌํ”„)๋ฅผ 1 ์ฆ๊ฐ€ ์‹œํ‚ด
    3. ๊ตฌํ•ด์•ผํ•˜๋Š” k๋ฒˆ์งธ ์ˆ˜๋ฅผ ๊ตฌ๊ฐ„ํ•ฉ์„ ์ด์šฉํ•ด ๊ตฌํ•จ
    4. ๋น„๊ตํ• ๋•Œ ์™ผ์ชฝ ์ž์‹๊ณผ ๋น„๊ตํ•œ๋‹ค, ์™ผ์ชฝ ์ž์‹๋ณด๋‹ค ํฌ๋ฉด ๊ทธ ๊ตฌ๊ฐ„์„ ํฌํ•จํ•˜๋Š” ๊ฒƒ, ์™ผ์ชฝ ๊ตฌ๊ฐ„ํ•ฉ ๊ฐ’์„ ๋นผ์ฃผ๊ณ  ์˜ค๋ฅธ์ชฝ์„ ํƒ์ƒ‰ํ•˜๋ฉด ๋œ๋‹ค
    5. ์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ•ด์•ผ ํ•˜๋Š”๊ฒƒ์€ 1~N ๊นŒ์ง€์˜ ๊ตฌ๊ฐ„ํ•ฉ์ด K์ธ๋ฐ ๊ทธ ์ˆซ์ž N์„ ๊ตฌํ•˜๋ฉด ๋œ๋‹ค

public static int kth (int node, int start, int end, int k) {
	if (start == end) {
		return start; // ์ธ๋ฑ์Šค๋ฅผ ๋ฆฌํ„ด
	} else {
		int mid = (start+end)/2;
		// ์™ผ์ชฝ ์ž์‹ ๋…ธ๋“œ๋ณด๋‹ค ํ˜„์žฌ๊ฐ’์ด ํฌ๊ฑฐ๋‚˜ ๊ฐ™๋‹ค๋ฉด ์šฐ์ธก ํƒ์ƒ‰ํ•ด์•ผํ•จ 
		if (k > tree[2*node]) {
                    // (k๊ฐ’์€ ์™ผ์ชฝ ๊ตฌ๊ฐ„ํ•ฉ + ์˜ค๋ฅธ์ชฝ ๊ตฌ๊ฐ„ํ•ฉ์ด๋ฏ€๋กœ) ์˜ค๋ฅธ์ชฝ ๊ตฌ๊ฐ„์„ ํƒ์ƒ‰ํ• ๋•Œ๋Š” ์™ผ์ชฝ ๊ตฌ๊ฐ„ํ•ฉ์„ ๋นผ์ค˜์•ผํ•œ๋‹ค
		    return kth(2*node+1, mid+1, end, k-tree[node*2]); 
                }
		else // k<= tree[2*node] 
		{
        	     return kth(2*node, start, mid, k);
                }
	}
}

๋ฐฑ์ค€ 12899 ๋ฐ์ดํ„ฐ๊ตฌ์กฐ

์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ (Bottom up ๋ฐฉ์‹ + lazy propagation)

๋‹ค์ฐจ์› ์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ (multidimensional segment tree)

click

์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ with lazy propagation

  • ์ผ๋ฐ˜ ์„ธ๊ทธ๋จผํŠธ์™€ ๋‹ฌ๋ฆฌ ๊ตฌ๊ฐ„์„ ์—ฌ๋Ÿฌ๊ฐœ ์—…๋ฐ์ดํŠธ ํ•ด์ค˜์•ผ ํ• ๋•Œ ์ ์šฉ
  • ex) 0-10 ๋ฐฐ์—ด์ด ์žˆ์„๋•Œ 2-7 ๊ตฌ๊ฐ„ 1์”ฉ ์ฆ๊ฐ€, 3-10 ๊ตฌ๊ฐ„ 1์”ฉ ์ฆ๊ฐ€
    click

์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ with dynamic

click

์„ธ๊ทธ๋จผํŠธ ํŠธ๋ฆฌ with Persistent segment tree

click

Fenwick Tree

๋ฐฑ์ค€ ์ด๋ก  ์„ค๋ช… click

๋จธ์ง€ ์†ŒํŠธ ํŠธ๋ฆฌ

click
reference

public ArrayListinit (int left, int right, int pos) {
    int (left == right) {
        tree[pos] = new ArrayList<>();
        tree[pos].add(arr[left]);
        return tree[pos];
    }
    int mid = (left + right) /2;
    ArrayList leftArr = init(left, mid, pos*2);
    ArrayList rightArr = init(mid+1, right, pos*2+1);
    return tree[pos] = merge(leftArr, rightArr);
}


public ArrayList merge(ArrayList leftArr, ArrayList rightArr) {
    ArrayList returnArr = new ArrayList<>();
    int i = 0;
    int j = 0;
    leftLen = leftArr.size();
    riightLen = rightArr.size();

    while(i < leftLen && j < rightLen) {
        if (leftArr.get(i) <= rightArr.get(i)) {
            returnArr.add(leftArr.get(i);
            i++;
        } else { 
            returnArr.add(rightArr.get(j);
            j++;
        }
    }
    while (i < leftLen) {
        returnArr.add(left.get(i);
        i++;
    }
    while (j < rightLen) {
        returnArr.add(right.get(j);
        j++;
    }
    return returnArr;
}

ํŠธ๋ฆฌ dp

<๊ฐœ์š”> ๊ทธ๋ž˜ํ”„์—์„  ์–ด๋–ค ์ •์  u์— ๋Œ€ํ•œ ์ƒํƒœ๊ฐ€ ์ธ์ ‘ํ•œ ์ •์  v์— ๋Œ€ํ•œ ์ƒํƒœ๋กœ ์ •์˜๋˜๋ฉฐ ์ฐธ์กฐ ํˆฌ๋ช…ํ•˜๋‹ค๋ฉด dp๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
์ข€ ๋” ์‰ฌ์šด ๋ง๋กœ, ์ •์ u์— ๋Œ€ํ•œ ์ƒํƒœ๊ฐ€ ์ธ์ ‘ ์ •์  v์˜ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ ํ™”์‹์ด ์„ธ์›Œ์ง„๋‹ค๋ฉด, dp๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
ํŠธ๋ฆฌ์—์„  ์ข€ ํŠน์ˆ˜ํ•˜๊ฒŒ, ์ •์  u์˜ ์ƒํƒœ๊ฐ€ ์ธ์ ‘ ์ •์  v์˜ ์ƒํƒœ๋‚˜ ๋ฃจํŠธ์˜ ์ƒํƒœ๋กœ ์ •์˜ ๋œ๋‹ค๋ฉด dp๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
์ •์  u๋ฅผ ๋ฃจํŠธ๋กœ ํ•˜๋Š” ์„œ๋ธŒํŠธ๋ฆฌ์— ๋Œ€ํ•œ ์ƒํƒœ๋ฅผ ๋ฌป๋Š” ๋ฌธ์ œ๊ฐ€ ์ž์ฃผ ๋‚˜์˜จ๋‹ค.
dp๋Š” ๋ณดํ†ต ์„ ํ˜•์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ๊ณต๊ฐ„์—์„œ ์ด๋ฃจ์–ด์กŒ์ง€๋งŒ, ํŠธ๋ฆฌ๋Š” ๋น„์„ ํ˜• ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ํŠธ๋ฆฌ์—์„œ dp๋ฅผ ํ•˜๊ธฐ ์ „์—, ํƒ์ƒ‰ ์ˆœ์„œ๋ฅผ ๋ฏธ๋ฆฌ ์ •ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.
ํƒ์ƒ‰ ์ˆœ์„œ๋ฅผ ์ •ํ•˜๋Š” ๊ฒƒ์€ dfs๋ฅผ ๋Œ๋ฉด์„œ ๋‚˜์˜ค๋Š” ํŠธ๋ฆฌ, ์ฆ‰ dfs tree๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.
reference
reroot

  • ํŠธ๋ฆฌ ๊ตฌ์กฐ(root)๋ฅผ ๋ฐ”๊พธ๋ฉด์„œ ๋ฐฑํŠธ๋ž˜ํ‚นํ•˜์—ฌ ์ •๋‹ต ๊ตฌํ•˜๋Š” re-rooting
    click
    click
    click

  • ํ—ˆํ”„๋งŒ ํŠธ๋ฆฌ click

โš ๏ธ **GitHub.com Fallback** โš ๏ธ