NOIP2017 D1T3 列队

来源:互联网 发布:linux读取文件指定行 编辑:程序博客网 时间:2024/06/04 20:03

NOIP2017 D1T3 列队


考场上嘴巴AC最后沦为30暴力选手…加上第一天D1T2神奇的错了两个点…失去生涯最后一次AK机会啦qwq

其实没那么难写qwq

考虑用n+1个splay维护出过队的人的编号,包括每行前m1个,以及最后一列。直接模拟题意即可。

一个比较麻烦的事情是如果当前取的元素还没有出过队,需要计算这一行第y个没有出过队的人的位置。很容易用动态开点线段树维护。

由于splay每次操作只会做O(1)次操作,总的复杂度是O(nlogn+qlogn)

#include <bits/stdc++.h>using namespace std;const int MAXN = 5000005;int root[MAXN], lc[MAXN], rc[MAXN], tot = 0, dat[MAXN];void push(int &nd, int pos, int L, int R){    if (!nd) nd = ++tot;    dat[nd]++;    if (L == R) return;    int mid = (L+R)>>1;    if (pos <= mid) push(lc[nd], pos, L, mid);    else push(rc[nd], pos, mid+1, R);}int find_kth(int nd, int k, int L, int R){    if (L == R) return L;    int mid = (L+R)>>1, lcnt = mid-L+1-dat[lc[nd]];    if (k <= lcnt) return find_kth(lc[nd], k, L, mid);    else return find_kth(rc[nd], k-lcnt, mid+1, R);}int n, m, q;int remain[MAXN];int chl[MAXN][2], fa[MAXN], siz[MAXN];long long dt[MAXN];int top = 0;struct splay_tree{    int rt;    splay_tree()    { rt = 0; }    inline void update(int nd)    { siz[nd] = siz[chl[nd][0]]+siz[chl[nd][1]]+1; }    void zig(int nd)    {        int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;        int son = chl[nd][tp^1];        if (son) fa[son] = p;        if (g) chl[g][tg] = nd;        else rt = nd;        fa[p] = nd, fa[nd] = g, chl[p][tp] = son, chl[nd][tp^1] = p;        update(p), update(nd);    }    void splay(int nd, int tar = 0)    {        while (fa[nd] != tar) {            int p = fa[nd], g = fa[p], tp = chl[p][0] != nd, tg = chl[g][0] != p;            if (g == tar) { zig(nd); break; }            else if (tp == tg) zig(p), zig(nd);            else zig(nd), zig(nd);        }    }    int kth_ele(int k)    {        int nd = rt;        while (1) {            if (siz[chl[nd][0]]+1 == k) return splay(nd), nd;            else if (k <= siz[chl[nd][0]]+1) nd = chl[nd][0];            else k -= siz[chl[nd][0]]+1, nd = chl[nd][1];        }    }    long long del_kth(int k)    {        int nd = kth_ele(k);        int pre = chl[nd][0], nxt = chl[nd][1];        while (chl[pre][1]) pre = chl[pre][1];        while (chl[nxt][0]) nxt = chl[nxt][0];        if (!pre && !nxt) rt = 0;        else if (!pre) splay(nxt), chl[nxt][0] = 0, update(nxt);        else if (!nxt) splay(pre), chl[pre][1] = 0, update(pre);        else splay(pre), splay(nxt, pre), chl[nxt][0] = 0, update(nxt), update(pre);        return dt[nd];    }    void push_last(long long d)    {        int nd = ++top; dt[nd] = d, update(nd);        int pos = rt;        if (rt == 0) rt = nd;        else if (!chl[rt][1]) chl[rt][1] = nd, fa[nd] = rt, update(rt);        else {            while (chl[pos][1]) pos = chl[pos][1];            chl[pos][1] = nd, fa[nd] = pos;            for (register int i = nd; i; i = fa[i]) update(i);            splay(nd);        }    }    void display(int nd, int tab = 0)    {        for (int i = 1; i <= tab; i++) cerr << " ";        if (nd == 0) { cerr << "." << endl; return; }        else {            cerr << nd << " " << dt[nd] << " " << fa[nd] << " " << siz[nd] << endl;            display(chl[nd][0], tab+2), display(chl[nd][1], tab+2);        }    }} rgt, line[MAXN];int main(){    scanf("%d%d%d", &n, &m, &q);    for (int i = 1; i <= n; i++) {        rgt.push_last((long long)i*m), remain[i] = m-1;    }    for (int i = 1; i <= q; i++) {        int x, y;        scanf("%d%d", &x, &y);        if (y == m) {            long long d = rgt.del_kth(x);            printf("%lld\n", d), rgt.push_last(d);        } else if (y <= remain[x]) {            int pos = find_kth(root[x], y, 1, m-1);            long long id = (long long)(x-1)*m+pos;            printf("%lld\n", id);            remain[x]--, push(root[x], pos, 1, m-1);            long long p = rgt.del_kth(x);            line[x].push_last(p), rgt.push_last(id);        } else {            y -= remain[x];            long long id = line[x].del_kth(y), p = rgt.del_kth(x);            printf("%lld\n", id), line[x].push_last(p), rgt.push_last(id);        }    }    return 0;}
原创粉丝点击