Lightoj1188 Fast Queries(樹狀數組離線)

題意

給出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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章