BZOJ4552[HEOI2016/TJOI2016]排序

\[BZOJ4552[HEOI2016/TJOI2016] 排序\]

  • 呵呵本来是因为改不动校内模拟赛一道题然后想着做一道线段树分裂的板子题水一水算了,结果板子题做了一天
  • 自己垃圾无话可说
  • 主要操作就是分裂前\(K\)大,具体的就是在分裂时改变\(size\)就好了,但有一些细节要注意;合并比较好处理,就是普通的线段树合并
  • 对每个点开一颗动态开点的权值线段树,用一些权值线段树维护一一对应的有序区间,区间排序就是要将边缘的线段树分裂,然后中间的全部合到一起,还要用\(set\)维护一下这些线段树之间的关系;
  • 直接按照上面的定义实现的,写得丑的一比,在洛谷上还过不了,也许是它的数据有问题,好像别人的线段树分裂也是\(40\)分,不过\(BZOJ\)\(LOJ\)都过了.
#include <bits/stdc++.h>

typedef long long LL;
typedef std::pair<int, int> PII;

#define debug(...) fprintf(stderr, __VA_ARGS__)
#define st first
#define ed second

std::string procStatus()
{
    std::ifstream buf("/proc/self/status");
    return std::string(std::istreambuf_iterator<char>(buf), std::istreambuf_iterator<char>());
}

inline int read(int Num = 0, int Flag = 1)
{
    char c = getchar();

    for (; !isdigit(c); c = getchar())
        if (c == '-') 
            Flag = -1;
    for (;  isdigit(c); c = getchar())
        Num = Num*10 + c-'0';

    return Num *= Flag;
}

template <typename T> bool chkmax(T &a, T b) { return a < b? a = b, true : false; }
template <typename T> bool chkmin(T &a, T b) { return a < b? a = b, true : false; }

namespace SEGT
{

const int MAXT = 3e6 + 5;

int totN;
int stk[MAXT];
int lc[MAXT], rc[MAXT];
int sz[MAXT];

inline void memory_init()
{
    for (int i = MAXT - 1; i >= 1; --i) stk[++totN] = i;
}

inline void erase(int cur)
{
    lc[cur] = rc[cur] = sz[cur] = 0;
    stk[++totN] = cur;
}

void build(int &h, int l, int r, int p)
{
    h = stk[totN--];
    sz[h] = 1;
    if (l == r) return ;

    int mid = (l + r) >> 1;
    if (p <= mid) build(lc[h], l, mid, p);
    else build(rc[h], mid + 1, r, p);
}

int merge(int u, int v)
{
    if (!u || !v) return u ^ v;
    if (u == v) return 0;

    lc[u] = merge(lc[u], lc[v]);
    rc[u] = merge(rc[u], rc[v]);

    sz[u] += sz[v]; erase(v);
    return u;
}

void split(int u, int &v, int k)
{
    v = stk[totN--];

    if (sz[lc[u]] < k) {
        split(rc[u], rc[v], k - sz[lc[u]]);
    }
    else {
        std::swap(rc[u], rc[v]);
        if (sz[lc[u]] > k) 
            split(lc[u], lc[v], k);
    }

    sz[v] = sz[u] - k, sz[u] = k;
}

int query(int h, int l, int r, int k)
{
    if (l == r) return l;
    int mid = (l + r) >> 1;
    if (sz[lc[h]] >= k) return query(lc[h], l, mid, k);
    else return query(rc[h], mid + 1, r, k - sz[lc[h]]);
}

}

const int MAXN = 1e5 + 5;

int N, M;

std::set<PII> S;

int rt[MAXN];
int ty[MAXN];

//split [l, r] -> [l, mid], (mid, r]
void split(int l, int mid, int r)
{
    if (ty[l]) {
        rt[mid + 1] = rt[l];
        SEGT::split(rt[mid + 1], rt[l], r - mid);
    }
    else {
        SEGT::split(rt[l], rt[mid + 1], mid - l + 1);
    }
    ty[mid + 1] = ty[l];
}

int query(int pos)
{
    std::set<PII>::iterator it = S.lower_bound({pos, 0});
    if (it->st > pos) --it;

    if (ty[it->st]) {
        return SEGT::query(rt[it->st], 1, N, it->ed - pos + 1);
    }
    else {
        return SEGT::query(rt[it->st], 1, N, pos - it->st + 1);
    }

    return assert(false), 0;
}

int main()
{
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);

    SEGT::memory_init();

    N = read(), M = read();
    for (int i = 1; i <= N; ++i) {
        int p = read();
        SEGT::build(rt[i], 1, N, p);
        S.insert(PII(i, i));
    }

    S.insert(PII(N + 1, 0));

    for (int c = 1; c <= M; ++c) {
        int opt = read(), l = read(), r = read();

        std::set<PII>::iterator it = S.lower_bound({l, 0});
        if (it->st > l) --it;

        static int stk[MAXN]; int len0 = 0;
        static PII add[MAXN]; int len1 = 0;
        static PII del[MAXN]; int len2 = 0;

        for (add[++len1] = {l, r}; it->st <= r; ++it) {
            del[++len2] = {it->st, it->ed};

            if (it->st < l) {
                split(it->st, l - 1, it->ed);
                add[++len1] = {it->st, l - 1};
            }
            else if (it->ed <= r) {
                stk[++len0] = it->st;
            }
            if (it->ed > r) {
                split(std::max(it->st, l), r, it->ed);
                stk[++len0] = std::max(it->st, l);
                add[++len1] = {r + 1, it->ed};
            }
        }

        for (int i = 1; i <= len0; ++i) {
            SEGT::merge(rt[l], rt[stk[i]]);
        }

        for (int i = 1; i <= len2; ++i) {
            S.erase(del[i]);
        }
        for (int i = 1; i <= len1; ++i) {
            S.insert(add[i]);
        }
        ty[l] = opt;

        assert(SEGT::sz[rt[l]] == r - l + 1);
    }

    int pos = read();
    printf("%d\n", query(pos));
    
    return 0;
}

转载于:https://www.cnblogs.com/pbvrvnq/p/8723066.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值