C - Rotatable Array Editorial by en_translator
Type-\(1\) and type-\(2\) queries costs \(O(1)\) time each, but naively executing a type-\(3\) query costs \(O(N)\) time even if you perform the \(k\)-time repetition at once, imposing a total time complexity of \(O(NQ)\) at worst.
How can we deal with type-\(3\) queries?
In fact, we can rephrase the problem as follows without changing the answers:
- Regard that the sequence adopts \(0\)-based indexing. That is, reassign indices as \(A=(A_0,A_1,\dots,A_{N-1})\). For queries involving \(p\), subtract \(1\) from it right after you receive it.
- Initially, let \({\rm offset} = 0\).
- Process a type-\(1\) query by setting \(A_{(p+{\rm offset})\%N}\) to \(x\).
- Process a type-\(2\) query by printing \(A_{(p+{\rm offset})\%N}\).
- Process a type-\(3\) query by setting \({\rm offset}\) to \(({\rm offset} + k) \% N\).
Here, \(p\%q\) denotes the remainder when \(p\) is divided by \(q\).
In short, we optimize the type-\(3\) operation that originally costs \(O(N)\) time by replacing it an \(O(1)\) operation of just updating the value of \({\rm offset}\)
If you increment \({\rm offset}\), the operation of accessing \(A_0\) is done by referring to \(A_1\), and \(A_1\) to \(A_2\), \(\dots\), and \(A_{N-1}\) to \(A_0\). This is nothing but a replacement originally asked by type \(3\).
By this optimization, every query can be handled in \(O(1)\) time, and the problem can be solved in a total of \(O(N+Q)\) time.
Sample code (C++):
#include<bits/stdc++.h>
using namespace std;
int main(){
int N,Q;
cin >> N >> Q;
vector<int> A(N);
for(int i=0;i<N;i++){
A[i]=i+1;
}
int offset=0;
while(Q>0){
Q--;
int typ;
cin >> typ;
if(typ==1){
int p,x;
cin >> p >> x;
p--;
A[(p+offset)%N]=x;
}
else if(typ==2){
int p;
cin >> p;
p--;
cout << A[(p+offset)%N] << "\n";
}
else{
int k;
cin >> k;
offset+=k;
offset%=N;
}
}
return 0;
}
posted:
last update: