NOIP2017 列队
这题看上去 fhq_Treap 一脸可做
看完 ** 的数据范围就不可做了
毕竟 d2t3 ,得有点骚操作的
我们发现操作次数并不多
可以试着“动态开点”
就是用到这个位置的时候再给它开辟一个节点
不用就和其他不用的连为一体作为一个节点就好了
挺麻烦不过代码并不长
核心部分代码:
pair<int, int> Split(int cur, ll k) {
if(!cur || !k) return make_pair(0, cur);
pair<int, int> res;
if(t[lson].siz >= k) {
res = Split(lson, k);
lson = res.second;
pushup(cur);
res.second = cur;
} else if(t[lson].siz + t[cur].len() >= k) {
register ll l = t[cur].l, r = t[cur].r;
int newrt;
k -= t[lson].siz;
t[cur].rerange(l, l + k - 1ll);
newrt = newnode(l + k, r);
res.second = Merge(newrt, rson);
rson = 0;
if(t[cur].len() <= 0) cur = lson;
pushup(cur);
res.first = cur;
} else {
res = Split(rson, k - t[lson].siz - t[cur].len());
rson = res.first;
pushup(cur);
res.first = cur;
}
return res;
}
意思就是说, 如果当前的区间是我想要操作的区间(要 Split 的区间),我就给它多开另一个节点,让他们两个作为裂开后的左右两部分
根据 fhq_Treap 的经典 Split 操作的过程,我们不难写出上面代码的细节
需要额外注意的就是在 newnode 的时候需要把节点的 size 搞一下
完整代码:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<ctime>
#define lson t[cur].ch[0]
#define rson t[cur].ch[1]
using namespace std;
typedef long long ll;
const int MAXN = 300005;
struct Node{
ll siz, l, r;
int ch[2], prio;
Node() {ch[0] = ch[1] = 0; siz = l = r = 0ll;}
inline void clear() {
ch[0] = ch[1] = prio = 0;
siz = l = r = 0ll;
return;
}
inline void rerange(ll x, ll y) {
l = x;
r = y;
return;
}
inline ll len() {
return r - l + 1ll;
}
}t[MAXN * 16];
int n, m, q, poolcur;
ll Root[MAXN];
inline int newnode(ll l, ll r) {
if(l > r) return 0;
register int cur = ++poolcur;
t[cur].clear();
t[cur].l = l;
t[cur].r = r;
t[cur].siz = t[cur].len();
t[cur].prio = rand();
return cur;
}
inline void pushup(int cur) {
t[cur].siz = t[lson].siz + t[rson].siz + t[cur].len();
return;
}
int Merge(int x, int y) {
if(!x) return y; if(!y) return x;
if(t[x].prio < t[y].prio) {
t[x].ch[1] = Merge(t[x].ch[1], y);
pushup(x);
return x;
} else {
t[y].ch[0] = Merge(x, t[y].ch[0]);
pushup(y);
return y;
}
}
pair<int, int> Split(int cur, ll k) {
if(!cur || !k) return make_pair(0, cur);
pair<int, int> res;
if(t[lson].siz >= k) {
res = Split(lson, k);
lson = res.second;
pushup(cur);
res.second = cur;
} else if(t[lson].siz + t[cur].len() >= k) {
register ll l = t[cur].l, r = t[cur].r;
int newrt;
k -= t[lson].siz;
t[cur].rerange(l, l + k - 1ll);
newrt = newnode(l + k, r);
res.second = Merge(newrt, rson);
rson = 0;
if(t[cur].len() <= 0) cur = lson;
pushup(cur);
res.first = cur;
} else {
res = Split(rson, k - t[lson].siz - t[cur].len());
rson = res.first;
pushup(cur);
res.first = cur;
}
return res;
}
inline void build() {
for(int i = 1; i <= n; ++i)
Root[i] = newnode(((ll)i - 1ll) * (ll)m + 1ll, (ll)i * (ll)m - 1ll);
Root[0] = newnode((ll)m, (ll)m);
int cur;
for(int i = 2; i <= n; ++i) {
cur = newnode((ll)i * (ll)m, (ll)i * (ll)m);
Root[0] = Merge(Root[0], cur);
}
return;
}
inline void work(ll x, ll y) {
pair<int, int> pre1, per1, pre2, per2;
if(y != m) {
pre1 = Split(Root[0], x);
per1 = Split(pre1.first, x - 1ll);
pre2 = Split(Root[x], y);
per2 = Split(pre2.first, y - 1ll);
printf("%lld\n", t[per2.second].l);
Root[0] = Merge(Merge(per1.first, pre1.second), per2.second);
Root[x] = Merge(Merge(per2.first, pre2.second), per1.second);
} else {
pre1 = Split(Root[0], x);
per1 = Split(pre1.first, x - 1ll);
printf("%lld\n", t[per1.second].l);
Root[0] = Merge(Merge(per1.first, pre1.second), per1.second);
}
return;
}
int main() {
// freopen("dui.in", "r", stdin);
// freopen("dui.out", "w", stdout);
srand(time(NULL));
scanf("%d%d%d", &n, &m, &q);
build();
ll x, y;
while(q--) {
scanf("%lld%lld", &x, &y);
work(x, y);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}