백준) 스위치_1395

2022. 2. 2. 16:49·알고리즘/백준

https://www.acmicpc.net/problem/1395

 

🐢 설명

인덱스드 트리 + 천천히 갱신되는 트리 활용이다. 이러한 유형의 문제들의 특징은 값의 변경이 특정 인덱스 하나가 아니라 범위로 주어진다는 특징이 있다.

 

하나의 값 변경에는 logN이 소요되고 범위가 1~N으로 주어지면 NlogN, 이러한 쿼리가 M번 주어지면 M * N * log N이 되어 N^2을 넘어가는 시간복잡도를 갖게된다. 따라서 시간복잡도 개선을 위해 값 변경이 이뤄지는 구간에 대해서 동일한 변경이 이뤄지는 노드들의 공통 부모에만 변경사항을 쌓아놓고 실제 변경이 필요할 때 자식노드로 변경해야할 값을 적용하도록 하는 지연 갱신 방식이 사용된다.

 

예를들어서 1~8번 노드가 존재한다고 하자. 이때 update(1, 8, 10)으로 1~8번 노드에 +10을 하라는 명령이 오면 이를 각 노드에 모두 전파하지 않고, 1~8의 공통 부모에만 +10을 적용하게 한다. 만약 update(1, 8, diff)가 100번 오더라도 공통 부모에만 diff 값을 적용하다가 실제 query(1, 8)을 물으면 그때 합산 diff를 자식노드에 전달한다.

 

이 경우에는 구간의 스위치를 키고 끄고 하므로 각 트리 노드는 자식 노드의 켜진 스위치 개수를 갖도록 한다. 이후 스위치 반전 명령이 오면 (하위 노드 개수 - 현재 켜진 개수)가 현재 켜진 개수로 변경되므로 이를 현재 노드 값으로 변경한다. 이후 자식 노드의 지연 변경 배열에 기록을 하기 위해 1이면 0으로, 0이면 1로 변경한다.

 

기존 인덱스드 트리 구조에서 updateLazy() 함수를 추가해서 변경사항이 있다면 적용하고, 자식에게 변경사항을 상속하고 자신의 변경사항은 적용됐으므로 0으로 지우면 된다. 이 함수는 update()에도 넣고, query()에도 넣어줘야 한다.

 

🐢코드
package 인덱스트리;

import java.io.*;
import java.util.*;

public class 스위치_1395 {
	static int N;
	static int M;
	static int S;
	static int[] lazy;
	static int[] tree;
	static StringBuilder answer = new StringBuilder();

	public static void main(String[] args) throws Exception {
	    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	    StringTokenizer st;

		st = new StringTokenizer(br.readLine());
		N = Integer.parseInt(st.nextToken());
		M = Integer.parseInt(st.nextToken());
		S = 1;
		while (S < N) S *= 2;
		lazy = new int[S * 2];
		tree = new int[S * 2];

		for (int i = 0; i < M; i++) {
			st = new StringTokenizer(br.readLine());
			int cmd = Integer.parseInt(st.nextToken());
			int queryLeft = Integer.parseInt(st.nextToken());
			int queryRight = Integer.parseInt(st.nextToken());

			if (cmd == 0) {
				updateRange(1, 1, S, queryLeft, queryRight);
			} else if (cmd == 1) {
				int count = query(1, 1, S, queryLeft, queryRight);
				answer.append(count).append("\n");
			}
		}

		System.out.print(answer);
	}

	private static void updateRange(int node, int start, int end, int queryLeft, int queryRight) {
		updateLazy(node, start, end);

		if (queryLeft > end || queryRight < start) return;

		if (queryLeft <= start && end <= queryRight) {
			tree[node] = (end - start + 1) - tree[node];

			if (start != end) {
				lazyTurn(node * 2);
				lazyTurn(node * 2 + 1);
			}
			return;
		}

		int mid = (start + end) / 2;
		updateRange(node * 2, start, mid, queryLeft, queryRight);
		updateRange(node * 2 + 1, mid + 1, end, queryLeft, queryRight);
		tree[node] = tree[node * 2] + tree[node * 2 + 1];
	}

	private static void updateLazy(int node, int start, int end) {
		if (lazy[node] != 0) {
			tree[node] = (end - start + 1) - tree[node];

			if (start != end) {
				lazyTurn(node * 2);
				lazyTurn(node * 2 + 1);
			}

			lazy[node] = 0;
		}
	}

	private static int query(int node, int start, int end, int queryLeft, int queryRight) {
		updateLazy(node, start, end);

		if (queryLeft > end || queryRight < start)
			return 0;

		if (start == end)
			return tree[node];

		if (queryLeft <= start && end <= queryRight)
			return tree[node];

		int mid = (start + end) / 2;
		return query(node * 2, start, mid, queryLeft, queryRight) +
				query(node * 2 + 1, mid + 1, end, queryLeft, queryRight);
	}

	private static void lazyTurn(int node) {
		lazy[node] = lazy[node] == 1 ? 0 : 1;
	}
}
🐢 마무리
반응형
저작자표시 비영리 변경금지 (새창열림)

'알고리즘 > 백준' 카테고리의 다른 글

(백준) 프린트전달 _ 23887  (0) 2022.03.30
(백준) 트리의 독립집합 _ 2213  (0) 2022.03.27
(백준) 달리기_2517  (0) 2022.02.02
(백준) 강수량 _ 2094  (0) 2022.02.02
(백준) 점심메뉴 _ 12099  (0) 2021.12.29
'알고리즘/백준' 카테고리의 다른 글
  • (백준) 프린트전달 _ 23887
  • (백준) 트리의 독립집합 _ 2213
  • (백준) 달리기_2517
  • (백준) 강수량 _ 2094
구름뭉치
구름뭉치
구름의 개발일기장
    반응형
  • 구름뭉치
    구름 개발일기장
    구름뭉치
  • 전체
    오늘
    어제
    • ALL (289) N
      • 프로젝트 (23)
        • 토스페이먼츠 PG 연동 시리즈 (12)
        • JWT 방식 인증&인가 시리즈 (6)
        • 스우미 웹 애플리케이션 프로젝트 (1)
        • 스프링부트 기본 보일러 플레이트 구축 시리즈 (2)
        • 마이크로서비스 아키텍쳐 시리즈 (1)
      • 스프링 (43)
        • 스프링부트 API 설계 정리 (8)
        • 스프링부트 RestAPI 프로젝트 (18)
        • 스프링부트 WebSocket 적용기 (3)
        • 스프링 JPA 정리 시리즈 (5)
        • 스프링 MVC (5)
        • 스프링 배치 (2)
        • 토비의 스프링 정리 (2)
      • 기술 학습 (5) N
        • 아파치 카프카 (9)
        • 클린 코드 (4)
        • 디자인 패턴의 아름다움 (2)
        • 모던 자바 인 액션 (7)
        • JVM 스레드 딥다이브 (7)
      • Web (25)
        • 정리글 (20)
        • GraphQL 정리글 (2)
        • Jenkins 정리글 (3)
      • 취업 (6)
      • CS (77)
        • 네트워크 전공 수업 정리 (11)
        • OSI 7계층 정리 (12)
        • 운영체제 정리 (19)
        • 데이터베이스 정리 (5)
        • MySql 정리 (17)
        • GoF의 Design Pattern 정리 (12)
      • 알고리즘 (70)
        • 백준 (56)
        • 프로그래머스 (12)
        • 알고리즘 정리본 (1)
      • 기초 지식 정리 (2)
      • 일상 (8)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    동유럽
    류블라냐
    레이저
    마우스
    mx master s3 for mac
    크로아티아
    부다페스트
    키보드 손목 받침대
    마우스 패드
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
구름뭉치
백준) 스위치_1395
상단으로

티스토리툴바