baekjoon

[백준] 12844 XOR

윤만석 2023. 7. 26. 17:05

 

문제

크기가 N인 수열 A0, A1, ..., AN-1이 주어졌을 때, 다음 두 종류의 쿼리를 수행해보자.

  • 1 i j k: Ai, Ai+1, ..., Aj에 k를 xor한다.
  • 2 i j: Ai, Ai+1, ..., Aj를 모두 xor한 다음 출력한다.

입력

첫 번째 줄에 수열의 크기 N이 주어진다.

두 번째 줄에는 A0, A1, ..., AN-1이 차례대로 주어지며, 공백 한 칸으로 구분되어져 있다.

세 번째 줄에는 쿼리의 개수 M이 주어지고, 다음 M개의 줄에 쿼리가 한 줄에 하나씩 주어진다.

출력

2번 쿼리의 결과를 모두 출력한다.

제한

  • 1 ≤ N, M ≤ 500,000
  • 0 ≤ Ai ≤ 100,000
  • Ai는 정수
  • 쿼리 1, 2
    • 0 ≤ i ≤ j < N
  • 쿼리 1
    • 0 ≤ k ≤ 100,000
    • k는 정수

 

LazyProp문제입니다.

다른 XOR문제와 다른점은 2번쿼리가 i부터j까지 모두 xor한 값을 출력하는것입니다.

따라서 업데이트쿼리에서 자식노드 둘을 xor하면 되는데...

 

삽질을 좀 했습니다.....

세그트리의 n번 노드를 검사할때, n번 노드가 포함하는 범위 내의 숫자들이 홀수개면 seg[n]은 ^k를 해줘야합니다.

왜냐하면 ^k ^k 두번하면 제자리이기 때문입니다.

이는 propagation함수에서 사용하는 논리입니다.

 

업데이트함수에서 seg트리를 갱신할때, 굳이 홀/짝을 나누지 않고 그냥 자식노드 둘을 xor해주면 됩니다.

이때 범위를 넘어가더라도 seg[child]를 반환해주어야 xor할때 이상한값을 출력하지 않습니다.

 

#include<bits/stdc++.h>
#define FAST ios_base::sync_with_stdio(false),cin.tie(NULL);
#define mset(v) memset(v,0,sizeof(v));
#define rep(i,a) for(int i=0;i<a;++i)
#define REP(i,a) for(int i=1;i<=a;++i)

using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
typedef tuple<int, int, int>ti;
typedef vector<int> vi;
typedef vector<vector<int>> vvi;
int dy[] = { -1,0,1,0 }, dx[] = { 0,1,0,-1 }, INF = 987654321;
int N, M, a[500001], seg[2000004], lazy[2000004];
int init(int l, int r, int n) {
	if (l == r) {
		return seg[n] = a[l];
	}
	int mid = (l + r) / 2;
	return seg[n] = init(l, mid, n * 2) ^ init(mid + 1, r, n * 2 + 1);
}
void propagate(int l, int r, int n) {
	if (lazy[n]) { //lazy가 존재하면
		if (l != r) {//자식노드가 있다면 lazy를 옮겨주고
			lazy[n * 2] ^= lazy[n];
			lazy[n * 2 + 1] ^= lazy[n];
		}
		if ((r - l + 1) % 2)seg[n] ^= lazy[n]; //만약 현재노드에서 포함하는 범위가 홀수라면 seg값이 갱신됩니다
		lazy[n] = 0;
	}
}
int update(int l, int r, int n, int f, int t, int k) {
	propagate(l, r, n);
	if (r < f || t < l)return seg[n]; //범위를 넘어서더라도 부모노드에서 xor을 해주어야하므로 seg[n]을 반환합니다.
	if (f <= l && r <= t) {
		lazy[n] ^= k;
		propagate(l, r, n);
		return seg[n];
	}
	int mid = (l + r) / 2;
	return seg[n]=update(l, mid, n * 2, f, t, k)^update(mid+1,r,n*2+1,f,t,k);
}
int query(int l, int r, int n, int f, int t) {
	propagate(l, r, n);
	if (r < f || t < l)return 0;
	if (f <= l && r <= t)return seg[n];
	int mid = (l + r) / 2;
	return query(l, mid, n * 2, f, t) ^ query(mid + 1, r, n * 2 + 1, f, t);
}
int main() {
	FAST;
	cin >> N;
	REP(i, N)
		cin >> a[i];
	init(1, N, 1);
	cin >> M;
	while (M--) {
		int x;
		cin >> x;
		if (x == 1) {
			int f, t, k;
			cin >> f >> t >> k; //f부터t까지 k XOR한다
			update(1, N, 1, f + 1, t + 1, k);
		}
		else {
			int f, t;
			cin >> f >> t; //t의 값 출력
			cout << query(1, N, 1, f + 1, t + 1) << "\n";
		}
	}
}