upc 2224 Boring Counting (线段树+离线or主席树)+离散化

来源:互联网 发布:python机器人编程 ros 编辑:程序博客网 时间:2024/05/17 08:01

题意:

1~n个数,询问l~r区间,值范围在A~B的个数。


思路:

线段树+离线(肉鸽跟我说的思路,以前真没碰到,线段树的花样太多了),用树状数组替代线段树也可以。

首先先全部接收全部的询问, 然后再把每个询问区间,分为两个区间。例如2-8 -> 1-1和1-8。

然后根据区间右端点从小到大排序,然后边更新线段树边查询,把查询的结果保存起来即可。


code(线段树):

#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std; const int N = 50000+5;typedef long long LL;#define lson l, mid, rt<<1#define rson mid+1, r, rt<<1|1#define start 1, n, 1 int n, m;int res[N];int a[N];int st[N<<2]; struct Seg {    int l, r, a, b;    int rank;    bool operator < (const Seg &b) const {        return r < b.r;    }}seg[N<<1]; void update(int l, int r, int rt, int idx) {    if(l == r) {        st[rt]++;        return ;    }    int mid = (l+r)>>1;    if(idx <= mid) update(lson, idx);    else update(rson, idx);    st[rt] = st[rt<<1] + st[rt<<1|1];} int query(int l, int r, int rt, int x, int y) {    if(x <= l && y >= r) {        return st[rt];    }    int mid = (l+r)>>1;    int ret = 0;    if(x <= mid) ret += query(lson, x, y);    if(y > mid) ret += query(rson, x, y);    return ret;} struct Discretization {    int a[N], n;    void init() {        n = 0;    }    inline void add(int val) {        a[n++] = val;    }    void ok() {        sort(a, a+n);        n = unique(a, a+n)-a;    }    inline int find(int val) {        return lower_bound(a, a+n, val)-a+1;    }}lsh; void solve() {    int cnt = 0;    {        int l, r, a, b;        for(int i = 0;i < m; i++) {            scanf("%d%d%d%d", &l, &r, &a, &b);            seg[cnt++] = (Seg){1, r, a, b, i};            if(l != 1) seg[cnt++] = (Seg){1, l-1, a, b, i};        }    }    sort(seg, seg+cnt);    int cur = 0;    for(int i = 0;i < cnt; i++) {        while(cur < seg[i].r) {            cur++;            update(start, lsh.find(a[cur]));        }        int l = lsh.find(seg[i].a), r = lsh.find(seg[i].b);        if(lsh.a[r-1] > seg[i].b) r--;        if(l > r) continue;        int &t = res[seg[i].rank];        t = query(start, l, r) - t;    }    for(int i = 0;i < m; i++) {        printf("%d\n", res[i]);    }}         int main() {    int T, cas = 0;    scanf("%d", &T);    while(T--) {        printf("Case #%d:\n", ++cas);        scanf("%d%d", &n, &m);        memset(st, 0, sizeof(st));        memset(res, 0, sizeof(res));        lsh.init();        for(int i = 1;i <= n; i++) {            scanf("%d", &a[i]);            lsh.add(a[i]);        }        lsh.ok();        solve();    }    return 0;}


code(主席树):

#include <cstdio>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;  const int N = 50000+5;typedef long long LL;#define lson l, mid, rt<<1#define rson mid+1, r, rt<<1|1#define start 1, n, 1  int n, m;int res[N];int a[N];int st[N<<2];struct PP {    int l, r, val;}c[int(1e6)];  int cnt;int head[N];void update(int l, int r, int &rt, int idx) {    c[++cnt] = c[rt];    c[cnt].val++;    rt = cnt;    if(l == r) return ;    int mid = (l+r)>>1;    if(idx <= mid) update(l, mid, c[rt].l, idx);    else update(mid+1, r, c[rt].r, idx);}int query(int l, int r, int rt, int x, int y) {    if(x <= l && y >= r) return c[rt].val;    int ret = 0;    int mid = (l+r)>>1;    if(x <= mid) ret += query(l, mid, c[rt].l, x, y);    if(y > mid) ret += query(mid+1, r, c[rt].r, x, y);    return ret;} struct Discretization {    int a[N], n;    void init() {        n = 0;    }    inline void add(int val) {        a[n++] = val;    }    void ok() {        sort(a, a+n);        n = unique(a, a+n)-a;    }    inline int find(int val) {        return lower_bound(a, a+n, val)-a+1;    }}lsh;  void solve() {    for(int i = 1;i <= n; i++) {        int idx = lsh.find(a[i]);        head[i] = head[i-1];        update(1, lsh.n, head[i], idx);    }    int l, r, a, b;    for(int i = 1;i <= m; i++) {        scanf("%d%d%d%d", &l, &r, &a, &b);        int ll = lsh.find(a), rr = lsh.find(b);        if(lsh.a[rr-1] > b) rr--;        int res = 0;        if(ll <= rr)             res = query(1, lsh.n, head[r], ll, rr) - query(1, lsh.n, head[l-1], ll, rr);        printf("%d\n", res);    }}     int main() {    int T, cas = 0;    scanf("%d", &T);    while(T--) {        printf("Case #%d:\n", ++cas);        scanf("%d%d", &n, &m);         cnt = 0;        memset(st, 0, sizeof(st));        memset(c, 0, sizeof(c));        memset(head, 0, sizeof(head));         lsh.init();        for(int i = 1;i <= n; i++) {            scanf("%d", &a[i]);            lsh.add(a[i]);        }        lsh.ok();        solve();    }    return 0;}



0 0