Lightoj1188 Fast Queries(树状数组离线)

来源:互联网 发布:js跳转指定页面 编辑:程序博客网 时间:2024/06/07 15:46

题意

给出n个数,Q次询问l,r表示数组l到r区间内有多少种数字。

思路

离线处理每个区间,把区间按照r的值从小到大排序。用vis[...]数组记录每个数前面出现的最近的位置。处理到位置i时,如果前面出现过a[i],那么把前面的那个位置清0,然后标记新的位置,再就是求前缀和了。。。
const int maxn = 1e6 + 1234;struct Querys {    int l, r, idx;}p[maxn];bool cmp(const Querys& A, const Querys& B) {    return A.r < B.r;}int b[maxn], ans[maxn], vis[maxn], c[maxn];int n, q;void add(int i,int v) {    while(i <= n) {        b[i] += v;        i += lowbit(i);    }}int sum(int i) {    int res = 0;    while(i > 0) {        res += b[i];        i -= lowbit(i);    }    return res;}int main(int argc, const char * argv[]){        // freopen("in.txt","r",stdin);    // freopen("out.txt","w",stdout);    int kase;cin >> kase;    while(kase--) {        scanf("%d%d", &n, &q);        for (int i = 1;i <= n;++i)            scanf("%d", &c[i]);        memset(vis, 0, sizeof vis);        memset(b, 0, sizeof b);        for (int i = 1;i <= q;++i) {            scanf("%d%d", &p[i].l, &p[i].r);            p[i].idx = i;        }        sort(p + 1, p + 1 + q, cmp);        // for (int i = 1;i <= q;++i)        //     printf("[l = %d, r = %d]\n", p[i].l, p[i].r);        int cnt = 1;        for (int i = 1;i <= n;++i) {            add(i, 1);            if (vis[c[i]]) add(vis[c[i]], -1);            vis[c[i]] = i;            while(cnt <= q && p[cnt].r == i) {                ans[p[cnt].idx] = sum(p[cnt].r) - sum(p[cnt].l - 1);                cnt++;            }            if (cnt > q) break;        }        printf("Case %d:\n", ++nCase);        for (int i = 1;i <= q;++i)            printf("%d\n", ans[i]);    }    // showtime;    return 0;}
1 0