[SDOI2009]HH的项链

题目链接
【分析】

  • 如果 N ≤ 5 × 1 0 4 N \leq 5 \times 10^4 N5×104,这就是莫队的模板题了。。。
  • 但是 N ≤ 5 × 1 0 5 N \leq 5 \times 10^5 N5×105。。。
  • 仍然考虑离线处理
  • 将询问按左端点排序
  • 预处理出每一种颜色第一次出现的位置,以及每个位置的下一个同色位置
  • 用一个指针扫描每一个位置,表示当前的左端点
  • 每扫描一个位置,就在该位置的下一个同色位置加 1 1 1
  • 这样答案就是 S u m ( l , r ) Sum(l,r) Sum(l,r)
  • 可以用树状数组维护

【代码】

#include
#define b(x) ((x - 1) / sqn)
using namespace std;

const int maxn = 5e5 + 10;
const int maxm = 2e5 + 10;

int n, m, a[maxn << 2], sqn, tot, cnt[maxn << 2], ans[maxm << 2], sum = 0;
struct query
{
    int rnk;
    int l, r;
} q[maxm << 1];

struct cmp
{
    inline bool operator () (const query &x, const query &y)
    {
        if(b(x.l) == b(y.l))
            return x.r < y.r;
        return x.l < y.l;
    }
};

inline void add(int pos)
{
    if(++cnt[a[pos]] == 1)
        sum++;
}

inline void remove(int pos)
{
    if(--cnt[a[pos]] == 0)
        sum--;
}

inline int read()
{
    static int x;
    static char c;
    x = 0, c = getchar();
    while(!isdigit(c))
        c = getchar();
    while(isdigit(c))
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return x;
}

int main()
{
    n = read();
    for(int i = 1; i <= n; i++)
        a[i] = read();
    
    m = read(), sqn = (n * n / m);
    for(int i = 1; i <= m; i++)
    {
        q[i].l = read();
        q[i].r = read();
        q[i].rnk = i;
    }
    
    sort(q + 1, q + m + 1, cmp());
    int mol = 0, mor = 0;
    for(int i = 1; i <= m; i++)
    {
        int l = q[i].l, r = q[i].r, rnk = q[i].rnk;
        while(mol < l)
            remove(mol++);
        while(mor > r)
            remove(mor--);
        while(mol > l)
            add(--mol);
        while(mor < r)
            add(++mor);
        ans[rnk] = sum;
    }
    
    for(int i = 1; i <= m; i++)
        printf("%d\n", ans[i]);
    
    return 0;
}

你可能感兴趣的:([SDOI2009]HH的项链)