ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线段树二分及区间mex

2022-04-28 20:00:23  阅读:209  来源: 互联网

标签:二分 return int 线段 tr mid query mex


仓鼠的鸡蛋

思路:

把线段树权值全部置为m,维护区间最大值,每次优先找满足条件的左边的区间

const int N = 500010;
int cnt[N];
int a[N];
int n, m, k;
int tr[N << 2];
int M = 1;
void pushup(int p) {
    tr[p] = max(tr[p << 1] , tr[p << 1 | 1]);
}
void build(int n) {
    for (M = 1; M <= n + 5; M <<= 1);
    for (int i = 1; i <= n; i++) tr[i + M] = m;
    for (int i = M; i; i--) {
        pushup(i);
    }
}
void modify(int p, int v) {
    int pos=p;
    p = p + M;
    int t = tr[p];
    t += v;
    if (++cnt[pos] == k) t = 0;
    t = max(t, 0LL);
    tr[p] = t;
    for (p >>= 1; p; p >>= 1) pushup(p);
}
int query(int l, int r) {
    int ans = -1;
    for (l += M - 1, r += M + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
        if (~l & 1) ans = max(ans, tr[l ^ 1]);
        if (r & 1) ans = max(ans, tr[r ^ 1]);
    }
    return ans;
}
int find(int x, int l, int r) {
    if (l == r) {
        modify(l, -x);
        return l;
    }
    int mid = l + r >> 1;
    if (query(l, mid) >= x) return find(x, l, mid);
    else if (query(mid + 1, r) >= x) return find(x, mid + 1, r);
    return -1;
}
void solve(int Case) {
    scanf("%lld%lld%lld", &n, &m, &k);
    for (int i = 1; i <= n; i++) cnt[i] = 0;
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    build(n);
    for (int i = 1; i <= n; i++) {
        printf("%lld\n", find(a[i], 1, n));
    }
}

区间mex离线做法

思路:

只有0~n会对mex产生影响,使用线段树维护每个ai对应的最新的下标,区间维护整个区间的最小下标,
按照左端点排序,把小于r的点都放进去,然后对l进行二分,如果出现的最新的下标小于l,那么这个数字一定是mex的带选项,
ps:线段树初始化每个点为-1

代码:

const int N = 200010;
int a[N];
struct tree {
    int l, r;
    int mpos;
};
struct Segment_Tree {
    tree tr[N << 2];
    int pos[N];
#define ls(x) x<<1
#define rs(x) x<<1|1
    void pushup(tree &p, tree &l, tree &r) {
        p.mpos = min(l.mpos, r.mpos);
    }
    void pushup(int p) {
        pushup(tr[p], tr[ls(p)], tr[rs(p)]);
    }
    void build(int p, int l, int r) {
        if (l == r) {
            tr[p] = {l, r, -1};
            pos[l] = p;
        }
        else {
            tr[p] = {l, r};
            int mid = l + r >> 1;
            build(ls(p), l, mid);
            build(rs(p), mid + 1, r);
            pushup(p);
        }
    }
    void modify1(int p, int x, int y) {
        p = pos[x];
        tr[p] = {x, x, y};
        for (; p >>= 1;) pushup(p);
    }
    tree query(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) return tr[p];
        int mid = tr[p].l + tr[p].r >> 1;
        if (r <= mid) return query(ls(p), l, r);
        else if (l > mid) return query(rs(p), l, r);
        else {
            tree ret;
            auto left = query(ls(p), l, r);
            auto right = query(rs(p), l, r);
            pushup(ret, left, right);
            return ret;
        }
    }
    int find(int p, int l, int r, int x) {
        if (l == r) {
            return l;
        }
        int mid = l + r >> 1;
        if (query(p, l, mid).mpos < x) {
            return find(p << 1, l, mid, x);
        } else return find(p << 1 | 1, mid + 1, r, x);
    }
};
Segment_Tree ST;
struct T {
    int l, r, mex, ans, id;
    bool operator<(const T &t) const {
        return r < t.r;
    }
} Q[N];
int c[N];
#define lowbit(x) x&(-x)
void add(int x, int y) {
    for (; x < N; x += lowbit(x)) c[x] += y;
}
int ask(int x) {
    int res = 0;
    for (; x; x -= lowbit(x)) res += c[x];
    return res;
}
void solve(int Case) {
    int n = read(), m = read();
    for (int i = 1; i <= n; i++) {
        a[i] = read();
    }
    for (int i = 1; i <= m; i++) {
        auto&[l, r, _, __, id] = Q[i];
        l = read(), r = read();
        id = i;
    }
    ST.build(1, 0, n);
    sort(Q + 1, Q + 1 + m);
    int p = 1;
    for (int i = 1; i <= m; i++) {
        auto&[l, r, mex, __, id] = Q[i];
        //cout << l << ' ' << r << nline;
        for (int i = p; i <= r; i++) {
            if (a[i] <= n) {
                ST.modify1(1, a[i], i);
            }
        }
        p = r + 1;
        mex = ST.find(1, 0, n, l);
    }
    sort(Q + 1, Q + 1 + m, [](T a, T b) {return a.id < b.id;});
    for (int i = 1; i <= m; i++) {
        printf("%lld\n", Q[i].mex);
    }
}

little w and Discretization

思路:

离散化之后答案一定是这段大于区间的mex(从1开始算)的数的个数,求mex直接套上题,区间改为1~n+1,求大于区间内某个数的个数,同样是离线,使用线段树或树状数组

代码:

const int N = 300010;
int a[N];
struct tree {
    int l, r;
    int mpos;
};
struct Segment_Tree {
    tree tr[N << 2];
    int pos[N];
#define ls(x) x<<1
#define rs(x) x<<1|1
    void pushup(tree &p, tree &l, tree &r) {
        p.mpos = min(l.mpos, r.mpos);
    }
    void pushup(int p) {
        pushup(tr[p], tr[ls(p)], tr[rs(p)]);
    }
    void build(int p, int l, int r) {
        if (l == r) {
            tr[p] = {l, r, -1};
            pos[l] = p;
        }
        else {
            tr[p] = {l, r};
            int mid = l + r >> 1;
            build(ls(p), l, mid);
            build(rs(p), mid + 1, r);
            pushup(p);
        }
    }
    void modify1(int p, int x, int y) {
        p = pos[x];
        tr[p] = {x, x, y};
        for (; p >>= 1;) pushup(p);
    }
    tree query(int p, int l, int r) {
        if (tr[p].l >= l and tr[p].r <= r) return tr[p];
        int mid = tr[p].l + tr[p].r >> 1;
        if (r <= mid) return query(ls(p), l, r);
        else if (l > mid) return query(rs(p), l, r);
        else {
            tree ret;
            auto left = query(ls(p), l, r);
            auto right = query(rs(p), l, r);
            pushup(ret, left, right);
            return ret;
        }
    }
    int find(int p, int l, int r, int x) {
        if (l == r) {
            return l;
        }
        int mid = l + r >> 1;
        if (tr[p << 1].mpos < x) {
            return find(p << 1, l, mid, x);
        } else return find(p << 1 | 1, mid + 1, r, x);
    }
};
Segment_Tree ST;
struct T {
    int l, r, mex, ans, id;
    bool operator<(const T &t) const {
        return r < t.r;
    }
} Q[N];
int c[N];
#define lowbit(x) x&(-x)
void add(int x, int y) {
    for (; x < N; x += lowbit(x)) c[x] += y;
}
int ask(int x) {
    int res = 0;
    for (; x; x -= lowbit(x)) res += c[x];
    return res;
}
void solve(int Case) {
    int n = read();
    for (int i = 1; i <= n; i++) {
        a[i] = read();
    }
    int m = read();
    for (int i = 1; i <= m; i++) {
        auto&[l, r, _, __, id] = Q[i];
        l = read(), r = read();
        id = i;
    }
    ST.build(1, 1, n );
    sort(Q + 1, Q + 1 + m);
    int p = 1;
    for (int i = 1; i <= m; i++) {
        auto&[l, r, mex, __, id] = Q[i];
        for (int i = p; i <= r; i++) {
            if (a[i] <= n) {
                ST.modify1(1, a[i], i);
            }
        }
        p = r + 1;
        mex = ST.find(1, 1, n, l);
    }
    sort(Q + 1, Q + 1 + m, [](T a, T b) {return a.id < b.id;});
    using PII = pair<int, int>;
    vector<PII> v(n + 1);
    for (int i = 1; i <= n; i++) {
        auto &[x, y] = v[i];
        x = a[i], y = i;
    }

    sort(v.begin() + 1, v.end(), greater<PII>());
    sort(Q + 1, Q + 1 + m, [](T a, T b) {return a.mex > b.mex;});
    p = 1;
    for (int i = 1; i <= m; i++) {
        auto &[l, r, mex, ans, id] = Q[i];
        while (p <= n and v[p].first > mex) {
            add(v[p].second, 1);
            p++;
        }
        ans = (ask(r) - ask(l - 1));
    }
    sort(Q + 1, Q + 1 + m, [](T a, T b) {return a.id < b.id;});
    for (int i = 1; i <= m; i++) {
        printf("%lld\n", Q[i].ans);
    }
}

标签:二分,return,int,线段,tr,mid,query,mex
来源: https://www.cnblogs.com/koto-k/p/16204263.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有