1 of 8

L: XORed Array

全体FA: touhokudai (49:05)�オンサイトFA: touhokudai (49:05)

AC: 9/26

原案: zawatin, writer: amesyu

2 of 8

問題概要

長さNの非負正数列Aが与えられる。�Q回下記の操作を行った後のAを出力せよ。

  • L, R, X が与えられる。 i = L, L + 1, … , R について�Ai = Ai xor (X + i - L) と更新する。�
  • 1 N 2×105
  • 1 ≤ Q ≤ 5×105
  • 0 ≤ Ai < 230
  • 1 ≤ li < ri ≤ N
  • 0 ≤ xi < 230

3 of 8

解法

2kの位が0か1になるのは2k+1の周期がある。���������前半2kは0、後半2kが1になっている。

0

1

2

3

4

5

6

7

8

9

10

11

12

13

K = 0

0

1

0

1

0

1

0

1

0

1

0

1

0

1

K = 1

0

0

1

1

0

0

1

1

0

0

1

1

0

0

K = 2

0

0

0

0

1

1

1

1

0

0

0

0

1

1

K = 3

0

0

0

0

0

0

0

0

1

1

1

1

1

1

4 of 8

解法

値を +1 してみる。���������周期が左にずれた。(循環している)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

K = 0

1

0

1

0

1

0

1

0

1

0

1

0

1

0

K = 1

0

1

1

0

0

1

1

0

0

1

1

0

0

1

K = 2

0

0

0

1

1

1

1

0

0

0

0

1

1

1

K = 3

0

0

0

0

0

0

0

1

1

1

1

1

1

1

5 of 8

解法

i = 0, 1, 2 … N の順にAiに作用する寄与を求めていく時、�各ビット毎に2k+1の周期の配列を左に1回シフトを行う。

-> 1シフト行ったことにして1寄与する範囲をずらせばOK!

6 of 8

解法

kビット目におけるxの寄与の位置というのはxを2k+1で割ったあまりで求めることができる。毎回寄与は1回シフトを行うのでi = Lのときに挿入するときは位置をL回左にシフトした位置になることに注意。

�1寄与している範囲に含まれている個数が奇数ならば�A[i] = A[i] xor 2k で更新を行う。

7 of 8

解法

今回の制約ではxi < 2^30であるため k = 30 まで確かめる必要がある。(xi + N - 1)が最大値なのでk = 29 だと足りない(罠)��230+1の配列を作るのは絶望的... ��1. 使われる範囲の個数は少ないので利用する�2. 上位ビットは別の操作で代用する

8 of 8

解法

kが大きい部分は1寄与する範囲が大きいので直接範囲に作用させる。N ≤ 2×105 より 18 ≤ k ならば範囲は一個しかないため、imos法などを用いて範囲の最初に1、最後に1を立てておけばよい。

時間空間ともにO((N + Q)logN) で解けた。