주제 포털 : LOJ # 510 .
질문의 의미를 설명 :
주어진에서 \ (K \) 16 진수 펜윅 나무, 그러나 그것의 구현 문제입니다.
그래서 상기 정식 \ (\ mathrm lowbit {} ( x)는 \) 와 같은 \ (K \) 진수에서 \ (X \) 최저 비 - 제로 비트 값, 예를 들면, \ (\ mathrm {} lowbit \! \ 좌회전 (230 _ {. (5)} \ 오른쪽)! \ _ = {(30). (5)} \) .
add(x, v)
동작이 수행된다
때 \ (X \ 르 n \) , 실행 s[x] ^= v
및 \ (X는 \) 된다 \ (X + \ mathrm lowbit} {(X) \) 및 사이클이 계속.
query(x)
동작이 수행된다 :
주문 \ (ANS \) 의 초기 값 (\ 0 \) .
경우 \ (x> 0 \) , 실행 ans ^= s[x]
및 \ (X \) 된다 \ (X - \ mathrm lowbit} {(X) \) 와주기를 계속한다.
결국 반환 (ANS \) \ .
해결 방법 :
올바르게 기록과 달리, add
연산의 수는 동작하지 않는 동안 수행 \ (\는 O (K \ mathcal log_K N)는 \) 하지만 \ (\ mathcal O (N) \) 관찰 복잡도가 발생할 때 변화율 : (K = 3, X = 1 \) \ 시간, \ (X는 \) (10 진수)로 변경 \ (1 \ 2 \ 4를 \로 5 \ 7을 \ 8을 \ (10)..... \에 \ cdots \) .
찾을 수 \ (X 축 \) 에서 \ (K \) 이진 최저 비 - 제로 비트 위치는 그대로 유지하고, (A) 내로 비트들의 가장 아닌 값 \ (1, 2, 1, 2, \ ldots 단락 \ ) 주기.
다른 들어 \ (K \) , 우리가 지정된 최소 비 제로 비트의 값의 변화를 관찰, 일부는 결국로 바뀌 찾을 \ (0 \) , 더 이상 제로입니다, 다른 사람들이 가을 동안 루프.
분명히, 이것은 실제로 함수 \ (F (X) = 2 × \ BMOD K \) 성분 접속 루트 포리스트 내 고리이며 해당 그래프에 전사 공정 \ (0 \ 0 \)로 링에서와 \ (0 \) 결국 비 숫자 0을 향상시키는 가장 낮은 지점에 접속된다.
번호 이론은 나무 링 내에서 그들 각각의 깊이가 초과하지 않습니다라고 우리에게 이야기한다 \ (\ log_2 K \) , 루트 인 경우 어디 \ (0 \) 트리, 가장 낮은 수준 만 변경됩니다 내에서 기본 링 (\ \ log_K N \) 의 총 번호, \ (\ log_2 K \ 번 \ log_K N- 형 = \ log_2 \ N- 형) 는 폭력이 부분을 건너 뛸 수 있습니다.
경우 마지막 그렇지 떨어 \ (0 \) 위의 예를 참조하여 고리는, 후방으로 연장하는 무한 체인을 형성하는 것이지만,이 체인의 루프 부분의 인접한 위치들 사이의 차이 인 경우.
각 체인의 사전 아웃 경우, 각 체인이 접미사, 하나 열거 작동을 유지하기위한 트리 배열을 시작할 수 있습니다.
그러나,이 범위를 너무 크게하는 전처리 직접 때문에 쇄, 즉 직접 결정된 소수점 수를 승산하는 방법을 고려할 것이다 \ (X를 \) 에 첫 번째로, 현재 위치에서 여러 사슬이고, 될 수 직접적 펜윅 트리 동작 (물론,이 시간 범위는 여전히 매우 중요하지만, 위치의 변화의 해시에 의해 작은 배열에 매핑된다).
같은 토큰을 물었을 때 query
때 \ (X \) 으로 변경됩니다 \ (\ log_K N \) 먼저 결정, 조사를 지시 할 수 있도록 시간, 때마다 (X \) \ 체인에 직접 수정하지 않을 경우, (\ ANS \)가 필요하거나 차이가 프리픽스 체크 첨가하는 단일 지점이 될 수있는 것으로) 접미사 개정 대응 전의 동작 (단일 쇄 열거 따른 전류 펜윅 트리되도록하려면 고전 해시 넓은 범위의 이입 방법에 대한 펜윅 트리 동작.
다음 코드는 해시의 시간 복잡도를 가정한다 \ (\ mathcal O. (1) \) 후 총 시간 복잡도이다 \ (\ mathcal O (K \ 로그 N + Q \ log_K n \) N 기록 \) :
#include <cstdio>
const int HASH = 19260817, NUMS = 10000005;
int h[HASH], nxt[NUMS], to[NUMS], tot;
inline int Hasher(int val, int typ) {
int cyp = (val ^ val >> 1) % HASH;
for (int i = h[cyp]; i; i = nxt[i]) if (to[i] == val) return i;
return typ ? nxt[++tot] = h[cyp], to[tot] = val, h[cyp] = tot : 0;
}
typedef long long LL;
const int MK = 200005;
int N, K, Q, V[6], C;
inline void lowbit(int x, int &y, int &z) {
int s = 1, t = C;
while (t) { if (x % V[t] == 0) x /= V[t], s *= V[t]; --t; }
y = x % K, z = y * s;
}
int ltrs[MK][30], ntrs[MK][30];
LL lsum[MK][30], nsum[MK][30];
int arr[NUMS];
int main() {
scanf("%d%d%d", &N, &Q, &K);
for (LL x = K; x <= N; x *= x) V[++C] = x;
for (int i = 1; i < K; ++i) if ((i & -i) >= (K & -K))
ltrs[i * 2 % K][0] = lsum[i * 2 % K][0] = i,
ntrs[i][0] = i * 2 % K, nsum[i][0] = i;
for (int j = 0; j < 29; ++j)
for (int i = 1; i < K; ++i) if ((i & -i) >= (K & -K))
ltrs[i][j + 1] = ltrs[ltrs[i][j]][j],
lsum[i][j + 1] = lsum[i][j] + lsum[ltrs[i][j]][j],
ntrs[i][j + 1] = ntrs[ntrs[i][j]][j],
nsum[i][j + 1] = nsum[i][j] + nsum[ntrs[i][j]][j];
for (int i = 1; i <= Q; ++i) {
int op, x, y, z, v, d;
scanf("%d%d", &op, &x);
if (op == 1) {
scanf("%d", &v);
while (x <= N) {
lowbit(x, y, z);
if ((y & -y) >= (K & -K)) {
int id = 0, X = x, Y = y, w = z / y;
for (int j = 29; j >= 0; --j)
if (lsum[Y][j] < X / w)
id |= 1 << j,
X -= lsum[Y][j] * w,
Y = ltrs[Y][j];
++id;
for (int j = 0; x <= N; ++j) if (id >> j & 1) {
arr[Hasher(x, 1)] ^= v;
x += nsum[y][j] * w;
y = ntrs[y][j];
id += 1 << j;
}
break;
}
arr[Hasher(x, 1)] ^= v;
x += z;
}
} else {
int Ans = 0;
while (x) {
lowbit(x, y, z);
if ((y & -y) >= (K & -K)) {
int id = 0, X = x, Y = y, w = z / y;
for (int j = 29; j >= 0; --j)
if (lsum[Y][j] < X / w)
id |= 1 << j,
X -= lsum[Y][j] * w,
Y = ltrs[Y][j];
++id;
X = x, Y = y;
for (int j = 0; id; ++j, id >>= 1) if (id & 1) {
if ((d = Hasher(X, 0))) Ans ^= arr[d];
X -= lsum[Y][j] * w;
Y = ltrs[Y][j];
}
} else if ((d = Hasher(x, 0))) Ans ^= arr[d];
x -= z;
}
printf("%d\n", Ans);
}
}
return 0;
}