반응형
문제 요약
처음에 $a_i = i$인 길이 N짜리 배열 a가 주어진다. 다음 쿼리를 처리하자.
- x y가 주어지면 [x, y]를 제일 앞으로 옮긴다.
- x y가 주어지면 [x, y]를 제일 뒤로 옮긴다.
- x y가 주어지면 [x, y]에 위치한 카드들에 대해서 리플셔플을 한다.
N은 최대 100만, 쿼리 수는 최대 20만이다. 3번 쿼리는 구간의 길이가 1000을 넘지 않는다.
풀이
1, 2번은 스플레이트리로 쉽게 가능하다.
3번 쿼리고 [x, y]구간을 잘 모아준다음에 해당 서브트리를 inorder로 탐색해줘서 배열을 만들어준 다음에 잘 섞어준 뒤에 다시 inorder로 탐색하면서 노드의 값들을 바꿔주면 된다.
다행이 3번 쿼리에 들어오는 구간은 길이가 1000이 최대라서 위 방식으로 처리해도 된다.
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
struct Node {
Node *left, *right, *p;
ll sz;
int val;
bool inv;
Node() : left(nullptr), right(nullptr), p(nullptr) {};
} *root;
void push(Node *cur) {
if(!cur->inv) return ;
swap(cur->left, cur->right);
if(cur->left) cur->left->inv = !cur->left->inv;
if(cur->right) cur->right->inv = !cur->right->inv;
cur->inv = false;
}
void update(Node *cur) {
cur->sz = 1;
if(cur->left) {
cur->sz += cur->left->sz;
}
if(cur->right) {
cur->sz += cur->right->sz;
}
}
void rotate(Node *cur) {
Node *p, *b;
p = cur->p;
if(!p) return ;
Node *pp = p->p;
if(p->left == cur) {
p->left = b = cur->right;
cur->right = p;
}
else {
p->right = b = cur->left;
cur->left = p;
}
p->p = cur;
cur->p = pp;
if(b) b->p = p;
if(!pp) root = cur;
else {
if(pp->left == p) pp->left = cur;
else pp->right = cur;
}
update(p); update(cur);
}
void splay(Node *cur) {
while(cur->p) {
Node *p = cur->p;
Node *pp = p->p;
if(pp) {
if((pp->left == p) == (p->left == cur)) rotate(p);
else rotate(cur);
}
rotate(cur);
}
}
void findKth(ll k) {
Node *p = root;
push(p);
while(1) {
while(p->left && p->left->sz > k) {
p = p->left;
push(p);
}
if(p->left) k -= p->left->sz;
if(!k) break;
else --k;
p = p->right;
push(p);
}
splay(p);
}
void segment(int l, int r) {
findKth(l-1);
Node *p = root;
root = p->right;
root->p = nullptr;
findKth(r-l+1);
root->p = p;
p->right = root;
root = p;
}
int N, Q;
void init() {
Node *p;
root = p = new Node;
p->val = 0;
p->inv = false;
for(int i=1;i<=N;++i) {
p->right = new Node;
p->right->p = p;
p = p->right;
p->val = i;
p->inv = false;
}
p->right = new Node;
p->right->p = p;
p = p->right;
p->val = 0;
p->inv = false;
while(p) {
update(p); p = p->p;
}
}
void flip(int l, int r) {
segment(l,r);
Node *p = root->right->left;
p->inv = !p->inv;
}
void moveFront(int l, int r) {
if(l == 1) return ;
flip(l,r);
flip(1,l-1);
flip(1,r);
}
void moveBack(int l, int r) {
if(r == N) return ;
flip(l,r);
flip(r+1,N);
flip(l,N);
}
vector<int> a, odd, even;
int idx;
void get_num(Node *cur) {
if(!cur) return ;
push(cur);
get_num(cur->left);
a.push_back(cur->val);
get_num(cur->right);
}
void push_num(Node *cur) {
if(!cur) return ;
push(cur);
push_num(cur->left);
if(idx & 1) cur->val = odd[idx/2];
else cur->val = even[idx/2];
++idx;
push_num(cur->right);
}
void print(Node *cur) {
if(!cur) return ;
push(cur);
print(cur->left);
if(cur->val) cout << cur->val << ' ';
print(cur->right);
}
void shuffle(int b, int c) {
segment(b,c);
Node *p = root->right->left;
a.clear();
get_num(p);
int n = a.size();
int thr = (n+1)/2;
even = vector<int>(a.begin(), a.begin()+thr);
odd = vector<int>(a.begin()+thr, a.end());
idx = 0;
push_num(p);
}
int main() {
cin.tie(nullptr); ios::sync_with_stdio(false);
cin >> N >> Q;
init();
for(int i=0;i<Q;++i) {
int a,b,c;
cin >> a;
if(a == 1) {
cin >> b >> c;
moveFront(b,c);
}
else if(a == 2) {
cin >> b >> c;
moveBack(b,c);
}
else {
cin >> b >> c;
shuffle(b,c);
}
}
print(root);
cout << '\n';
return 0;
}
반응형
'Problem Solving > 문제풀이' 카테고리의 다른 글
백준 14858번 GCD 테이블과 연속 부분 수열 (0) | 2021.02.18 |
---|---|
백준 10755번 컴퓨터실 (0) | 2021.02.18 |
백준 16586번 Linked List (0) | 2021.02.17 |
백준 17607번 수열과 쿼리 31 (0) | 2021.02.17 |
백준 13543번 수열과 쿼리 2 (0) | 2021.02.17 |