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

题意:

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值