ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ๐ŸŒฒ Segment Tree 2 - ๋” ๋น ๋ฅธ update๋ฅผ ์œ„ํ•œ Lazy Propagation!
    ALicademy ๐Ÿ‘ฉ‍๐Ÿซ๐Ÿ‘จ‍๐Ÿซ/์•Œ๊ณ ๋ฆฌ์ฆ˜ 2020. 9. 1. 19:27

    ์›๋ณธ์€ ๋งํฌ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    Intro ๐Ÿš€

    ์ด์ „ ๊ธ€ ๋งˆ์ง€๋ง‰์— ๋ง์”€๋“œ๋ ธ๋“ฏ์ด segment tree์—์„œ ํŠน์ • ๊ตฌ๊ฐ„์„ updateํ•  ๋•Œ leaf node๋ฅผ ์ผ์ผ์ด ๋ฐฉ๋ฌธํ•ด์„œ updateํ•˜๋ฉด ์ค‘๋ณตํ•ด์„œ ๋ฐฉ๋ฌธํ•˜๋Š” ๋…ธ๋“œ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค. ์ด ๋•Œ๋ฌธ์— ์ •๋ง ๋งŽ์€ update ์—ฐ์‚ฐ์„ ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

     

    ๊ทธ๋ž˜์„œ ์˜ค๋Š˜์€ ๋” ๋น ๋ฅธ udpate๋ฅผ ์œ„ํ•œ ๊ธฐ๋ฒ•์ธ Lazy propagation๐Ÿ˜ด ์— ๋Œ€ํ•ด ๋ฐฐ์›Œ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

     

    Lazy Propagation ๐Ÿ˜ด

    ์ง€๊ธˆ๋ถ€ํ„ฐ ์—ฌ๋Ÿฌ๋ถ„์ด ๋…ธ๋“œ๋ฅผ ์ง์ ‘ updateํ•˜๋Š” ์ผ๊พผ๐Ÿ‘ท‍โ™€๏ธ๐Ÿ‘ท์ด๋ผ๊ณ  ์ƒ๊ฐํ•ด๋ด…์‹œ๋‹ค!

    ์—ฌ๋Ÿฌ๋ถ„์€ ์•„๋ž˜ ์˜ˆ์ œ์™€ ๊ฐ™์€ segment tree๋ฅผ ๋Œ์•„๋‹ค๋‹ˆ๋ฉด์„œ ๋…ธ๋“œ๋ฅผ udpateํ•ฉ๋‹ˆ๋‹ค.

     

     

    ๋งŒ์•ฝ arr์˜ 0๋ฒˆ์งธ๋ถ€ํ„ฐ 2๋ฒˆ์งธ ์ธ๋ฑ์Šค๊นŒ์ง€ updateํ•˜๋ผ๋Š” ์ž‘์—…์ด ๋“ค์–ด์˜ค๋ฉด ์—ฌ๋Ÿฌ๋ถ„์€ ๊ฐ๊ฐ์˜ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์žˆ๋Š” leaf node (์œ„ ์˜ˆ์ œ์—์„œ๋Š” 8, 9, 5๋ฒˆ์งธ ๋…ธ๋“œ)๋ฅผ ๋ฐฉ๋ฌธํ•œ ํ›„ ๊ฐ’์„ ์ˆ˜์ •ํ•˜๊ณ  ๊ทธ์— ๋”ฐ๋ผ ์กฐ์ƒ ๋…ธ๋“œ๋“ค์˜ ๊ฐ’๋„ ์ˆ˜์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

     

    ๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ ์—ฌ๋Ÿฌ๋ถ„์ด ์—ด์‹ฌํžˆ ์‹œ๊ฐ„ ๋“ค์—ฌ๊ฐ€๋ฉด์„œ ํ•˜๋‚˜ํ•˜๋‚˜ updateํ•œ ๋…ธ๋“œ๋ฅผ ํ•œ๋ฒˆ๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ์–ด๋–จ๊นŒ์š”? ์•„๋งˆ ๋‹น์‹ ์€ ํ—ˆํƒˆํ•˜๊ณ  ๋ฐฐ์‹ ๋‹นํ•œ ๊ธฐ๋ถ„์ด ๋“ค์ง€๋„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

     

    ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋‹น์‹ ์€ ์ด๋ ‡๊ฒŒ ๋งํ• ์ง€๋„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. '์ด์ œ๋ถ€ํ„ฐ ์‚๋šค์–ด ์งˆํ…Œ์•ผ! ๐Ÿ˜ค ์•ž์œผ๋กœ๋Š” updateํ•˜๋Š” ๊ฑฐ ๋‹ค ๋ฏธ๋ฃฐ๊บผ์•ผ! ์ •๋ง ํ•„์š”ํ•  ๋•Œ๋งŒ updateํ•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด update ์•ˆ ํ• ๊บผ๋‹ค ํฅ!๐Ÿ˜ค'

     

    ๋ฐ”๋กœ ์ด ์ƒ๊ฐ์œผ๋กœ๋ถ€ํ„ฐ Lazy propagation๐Ÿ˜ด์ด ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค!

    ์—ฌ๊ธฐ์„œ '์ •๋ง ํ•„์š”ํ•  ๋•Œ๋งŒ updateํ•˜๊ณ  ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด udpate ์•ˆ ํ•  ๊ฒƒ์ด๋‹ค'๋ผ๋Š” ๋ง์ด ์กฐ๊ธˆ ์ถ”์ƒ์ ์ž…๋‹ˆ๋‹ค.

    ์ •ํ™•ํžˆ ๋ง์”€๋“œ๋ฆฌ๋ฉด โœจLazy propagation์€ ํ›„์† ๋…ธ๋“œ๋ฅผ ์ ‘๊ทผํ•ด์•ผ ํ•  ๋•Œ๊นŒ์ง€ ํ›„์† ๋…ธ๋“œ๋ฅผ updateํ•˜๋Š” ๊ฒƒ์„ ๋ฏธ๋ฃน๋‹ˆ๋‹ค.โœจ

     

    ๋˜ํ•œ Lazy propagation์„ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” ๋ณดํ†ต segment tree๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฐฐ์—ด $tree[]$์™€ ํฌ๊ธฐ๊ฐ€ ๊ฐ™์€ ๋ฐฐ์—ด $lazy[]$ ๋ฅผ ์ด์šฉํ•ด lazy node๋ฅผ ํ‘œํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ $lazy[i]$๋Š” ๋…ธ๋“œ $tree[i]$๋ฅผ ์ ‘๊ทผํ•ด์•ผ ํ•  ๋•Œ ์ฆ๊ฐ€์‹œ์ผœ์•ผ ํ•  ๊ฐ’ (๋ฌธ์ œ์— ๋”ฐ๋ผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค) ์ž…๋‹ˆ๋‹ค.

     

    ๊ทธ๋ ‡๋‹ค๋ฉด ๋งŒ์•ฝ $lazy[i]$๊ฐ€ 0์ด๋ผ๋Š” ๊ฒƒ์€ ๋ฌด์Šจ ๋œป ์ผ๊นŒ์š”? ์—ฌ๋Ÿฌ๋ถ„์ด ์ƒ๊ฐํ•˜์‹œ๋Š” ๋Œ€๋กœ ๋…ธ๋“œ $tree[i]$๋Š” ๋ฌด์–ธ๊ฐ€ ํ•ด์•ผ ํ•  update๊ฐ€ ์—†๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ๐Ÿ™…‍โ™‚๏ธ

     

    ๊ทธ๋Ÿผ ์ง€๊ธˆ๋ถ€ํ„ฐ Lazy propagation์„ ์ด์šฉํ•œ update์™€ query์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

     

    Update

    update ํ•˜๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ 3๋‹จ๊ณ„๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.

     

    1. Laziness๋ฅผ ์—†์• ์„œ ํ˜„์žฌ ๋…ธ๋“œ ์›๋ž˜ ๊ฐ’์œผ๋กœ ๋งŒ๋“ค๊ธฐ. ๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ž์‹ ๋…ธ๋“œ์— lazy ํ‘œ์‹œํ•˜๊ธฐ.

    2. ํ˜„์žฌ ๋…ธ๋“œ๊ฐ€ updateํ•ด์•ผ ํ•  ๊ตฌ๊ฐ„์— ํฌํ•จ๋˜๋ฉด updateํ•˜๊ธฐ

    3. updateํ•  ์ ์ • ๊ตฌ๊ฐ„์„ ์ฐพ๊ธฐ ์œ„ํ•ด ์ž์‹ ๋…ธ๋“œ ๋ฐฉ๋ฌธ

     

    ๊ด€๋ จ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

     

    Query

    Query๋ฅผ ๊ตฌํ•˜๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ 2๋‹จ๊ณ„๋กœ ๋‚˜๋‰ฉ๋‹ˆ๋‹ค.

    1. Laziness๋ฅผ ์—†์• ์„œ ํ˜„์žฌ ๋…ธ๋“œ ์›๋ž˜ ๊ฐ’์œผ๋กœ ๋งŒ๋“ค๊ธฐ. ๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ž์‹ ๋…ธ๋“œ์— lazy ํ‘œ์‹œํ•˜๊ธฐ.

    2. Query์—์„œ ์š”๊ตฌํ•œ ์ ์ • ๊ตฌ๊ฐ„ ์ฐพ๊ธฐ ์œ„ํ•ด ์ž์‹ ๋…ธ๋“œ ๋ฐฉ๋ฌธ

    ๊ด€๋ จ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

     

    Let's do PS ๐Ÿ˜ธ

    Lazy propagation์— ๋Œ€ํ•ด ์ž˜ ์ดํ•ด๋˜์…จ๋‚˜์š”?

    ๊ทธ๋ ‡๋‹ค๋ฉด ํ•จ๊ป˜ BOJ 10999๋ฒˆ ๊ตฌ๊ฐ„ ํ•ฉ ๊ตฌํ•˜๊ธฐ2 ๋ฅผ ํ’€์–ด๋ด…์‹œ๋‹ค!

     

    ๋„์›€์ด ํ•„์š”ํ•˜์‹œ๋ฉด ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š” ๐Ÿ˜บ

    ๋”๋ณด๊ธฐ
    import java.io.BufferedReader;
    import java.io.InputStreamReader;
    
    public class BOJ_10999 {
    
    	public static void main(String[] args) throws Exception {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		String[] inputs = br.readLine().split(" ");
    		
    		int N = Integer.parseInt(inputs[0]);
    		int M = Integer.parseInt(inputs[1]);
    		int K = Integer.parseInt(inputs[2]);
    		
    		long[] arr = new long[N];
    		long[] sgmt = new long[4 * N];
    		long[] lazy = new long[4 * N];
    		
    		for(int i = 0; i < N; i++) {
    			arr[i] = Long.parseLong(br.readLine());
    		}
    		
    		build(arr, sgmt, 0, N - 1, 1);
    		
    		for(int i = 0; i < M + K; i++) {
    			inputs = br.readLine().split(" ");
    			int a = Integer.parseInt(inputs[0]);
    			int b = Integer.parseInt(inputs[1]);
    			int c = Integer.parseInt(inputs[2]);
    			long d = (inputs.length > 3) ? Integer.parseInt(inputs[3]) : 0;
    			
    			switch(a) {
    				case 1 :
    					update(sgmt, lazy, 0, N - 1, 1, b-1, c-1, d);
    					break;
    				case 2 :
    					System.out.println(query(sgmt, lazy, 0, N - 1, 1, b-1, c-1));
    					break;
    			}
    		}
    		
    	}
    	
    	public static void build(long[] arr, long[] sgmt, int lo, int hi, int idx) {
    		if(lo == hi) {
    			sgmt[idx] = arr[lo];
    			return;
    		}
    		
    		int mid = lo + (hi - lo) / 2;
    		build(arr, sgmt, lo, mid, 2 * idx);
    		build(arr, sgmt, mid + 1, hi, 2 * idx + 1);
    		
    		sgmt[idx] = sgmt[2 * idx] + sgmt[2 * idx + 1];
    	}
    	
    	public static void update(long[] sgmt, long[] lazy, int lo, int hi, int idx, int i, int j, long val) {
    		if(lazy[idx] != 0) {
    			sgmt[idx] += (hi - lo + 1) * lazy[idx];
    			
    			if(lo != hi) {
    				lazy[2 * idx] += lazy[idx];
    				lazy[2 * idx + 1] += lazy[idx];
    			}
    			
    			lazy[idx] = 0;
    		}
    		
    		if(hi < i || j < lo) return;
    		
    		if(i <= lo && hi <= j) {
    			sgmt[idx] += (hi - lo + 1) * val;
    			
    			if(lo != hi) {
    				lazy[2 * idx] += val;
    				lazy[2 * idx + 1] += val;
    			}
    			
    			return;
    		}
    		
    		int mid = lo + (hi - lo) / 2;
    		update(sgmt, lazy, lo, mid, 2 * idx, i, j, val);
    		update(sgmt, lazy, mid + 1, hi, 2 * idx + 1, i, j, val);
    		
    		sgmt[idx] = sgmt[2 * idx] + sgmt[2 * idx + 1];
    	}
    	
    	public static long query(long[] sgmt, long[] lazy, int lo, int hi, int idx, int i, int j) {
    		if(hi < i || j < lo) return 0;
    		
    		if(lazy[idx] != 0) {
    			sgmt[idx] += (hi - lo + 1) * lazy[idx];
    			
    			if(lo != hi) {
    				lazy[2 * idx] += lazy[idx];
    				lazy[2 * idx + 1] += lazy[idx];
    			}
    			
    			lazy[idx] = 0;
    		}
    		
    		if(i <= lo && hi <= j) return sgmt[idx];
    		
    		int mid = lo + (hi - lo) / 2;
    		return query(sgmt, lazy, lo, mid, 2 * idx, i, j) + 
    			   query(sgmt, lazy, mid + 1, hi, 2 * idx + 1, i, j);
    	}
    
    }
    

     

     

    Segment tree๋ถ€ํ„ฐ Lazy propagation๊นŒ์ง€ ์ž˜ ์ดํ•ด ๋˜์…จ๊ธธ ๋ฐ”๋ผ๋ฉฐ ๊ธ€์„ ๋งˆ์น˜๊ฒ ์Šต๋‹ˆ๋‹ค!

    ๋‹ค์Œ ๊ธ€์—์„œ ๋งŒ๋‚˜์š”~~~๐Ÿ‘‹๐Ÿ‘‹๐Ÿ‘‹

     

    ์ฐธ๊ณ 

    https://bowbowbow.tistory.com/4

    https://leetcode.com/articles/a-recursive-approach-to-segment-trees-range-sum-queries-lazy-propagation/

    ๋Œ“๊ธ€

Designed by Tistory.