牛客多校第一场J题(树状数组+离线处理)

牛客多校第一场J

题中问的是从1到i  和 j到n   虽然是取了两边  但也是区间处理问题

莫队可以做。。不过时间是个玄学  

正解做法是树状数组,先倍增区间  然后将所有的询问存下来按照右区间递增排序

用map记录 第一次出现和最后一次出现

#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
const int N = 3e5 + 10;
const int inf = 0x3f3f3f3f;
int a[N], n, m, ans[N], c[N];
map<int, int> mp;
int lowbit(int x)
{
    return x & -x;
}
void add(int i, int k)
{
    while (i <= n)
    {
        c[i] += k;
        i += lowbit(i);
    }
}
int sum(int i)
{
    int res = 0;
    while (i > 0)
    {
        res += c[i];
        i -= lowbit(i);
    }
    return res;
}
struct node
{
    int l, r, id;
} query[N];
bool cmp(node x, node y)
{
    return x.r < y.r;
}
int main()
{
    
    while (~scanf("%d%d", &n, &m))
    {
        mem(c, 0);
        mp.clear();
        //输入 ,  倍增
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            a[i + n] = a[i];
        } 

        for (int i = 0; i < m; i++)
        {
            scanf("%d%d", &query[i].r, &query[i].l);
            query[i].r += n;
            query[i].id = i;
        }
        n <<= 1;
        sort(query, query + m, cmp);

        int cur = 1; 
        for (int i = 0; i < m; i++)
        {
            for (int j = cur; j <= query[i].r; j++)
            {
                if (mp.find(a[j]) != mp.end())
                {
                    add(mp[a[j]], -1);
                }
                add(j, 1);
                mp[a[j]] = j;
            }
            cur = query[i].r + 1;
            ans[query[i].id] = sum(query[i].r) - sum(query[i].l - 1);
        }
        for (int i = 0; i < m; i++)
            printf("%d\n", ans[i]);
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/soul_97/article/details/81213642