NOIP2017 列队

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;
}

 

转载于:https://www.cnblogs.com/xcysblog/p/9343474.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值