Codeforces - 220B Little Elephant and Array(莫队模板题)

题意:

  m次查询。每次查询范围[L,R]中出现次数等于该数字的数字个数。

题解:

   由于分块,在每次询问中,同一块时l至多移动根号n,从一块到另一块也是最多2倍根号n。对于r,每个块中因为同一块是按y排序,所以最多移动根号n;一共根号n个块。注意l和r要分开考虑。

   要注意的是这道题需要离散一下数据。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1e5+10;
int n, m;
int l, r;
int a[maxn], b[maxn], d[maxn];
int blk;
int blg[maxn];
int ans;
int sum[maxn];
int out[maxn];
struct node {
    int x, y, id;
}c[maxn];
bool cmp(node u, node v) {
    return (blg[u.x]==blg[v.x])?u.y<v.y:u.x<v.x;
}
void update(int x, int t) {
    sum[d[x]] += t;
    if(sum[d[x]] == a[x])
    ans++;
    else if(sum[d[x]] == a[x]+t)
    ans--;
    
}
int main() {
    while(~scanf("%d%d", &n, &m)) {
        for(int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            b[i] = a[i];
        }
        sort(b+1, b+n+1);
        int num = unique(b+1, b+n+1)-b;
        for(int i = 1; i <= n; i++) d[i] = lower_bound(b+1, b+num+1, a[i])-b;
        blk = sqrt(n);
        for(int i = 1; i <= n; i++) blg[i] = (i-1)/blk+1;
        for(int i = 1; i <= m; i++) {
            scanf("%d%d", &c[i].x, &c[i].y);
            c[i].id = i;
        }
        sort(c+1, c+m+1, cmp);
        l = 1; r = 0;
        ans = 0;
        memset(sum, 0, sizeof(sum));
        for(int i = 1; i <= m; i++) {
            while(l < c[i].x) update(l++, -1);
            while(l > c[i].x) update(--l, 1);
            while(r < c[i].y) update(++r, 1);
            while(r > c[i].y) update(r--, -1);
            out[c[i].id] = ans;
        }
        for(int i = 1; i <= m; i++) printf("%d\n", out[i]);
    }
    return 0;
}
View Code

 

posted @ 2018-03-12 20:29  Pneuis  阅读(178)  评论(0编辑  收藏  举报