Codeforces 220B Little Elephant and Array

  和今年某道多校的题很像。离线+线段树区间修改、单点查询。按右端点将查询区间排序。扫描数列,假设当前数a第x次出现,那么当x>=a时,区间[pos[a][x-a]+1,pos[a][x-a+1]]上所有点+1;当x>a时,区间[pos[a][x-a-1]+1,pos[a][x-a]]上所有点-1,pos[a][x]表示数a第x次出现的位置,为了方便,设所有数第一次出现的位置为0。若当前扫描到的位置有查询区间的右端点,则在线段树上查询左端点处的值,即为该次查询的答案。

//Sep 1, 2012 6:14:56 AM 	bigoceanlhy 	220B - Little Elephant and Array 	GNU C++ 	Accepted 	200 ms 	8500 KB
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 100000+5;
int N, M, a[MAXN], s[MAXN], t[MAXN], r[MAXN], ans[MAXN];
int Tr[MAXN<<2], mark[MAXN<<2];
vector<int> pos[MAXN];
bool cmp(const int a, const int b)
{
    return t[a] < t[b];
}
void PushDown(int idx)
{
    int left = idx<<1, right = (idx<<1)^1;
    Tr[left] += mark[idx];
    mark[left] += mark[idx];
    Tr[right] += mark[idx];
    mark[right] += mark[idx];
    mark[idx] = 0;
}
void Update(int idx, int L, int R, int l, int r, int c)
{
    if (l <= L && R <= r)
    {
        Tr[idx] += c;
        mark[idx] += c;
        return;
    }
    if (mark[idx])
        PushDown(idx);
    int mid = (L+R)>>1, left = idx<<1, right = (idx<<1)^1;
    if (l <= mid)
        Update(left, L, mid, l, r, c);
    if (mid < r)
        Update(right, mid+1, R, l, r, c);
}
int Query(int idx, int L, int R, int x)
{
    if (x == L & R == x)
        return Tr[idx];
    if (mark[idx])
        PushDown(idx);
    int mid = (L+R)>>1, left = idx<<1, right = (idx<<1)^1;
    if (x <= mid)
        return Query(left, L, mid, x);
    else
        return Query(right, mid+1, R, x);
}
int main()
{
    scanf("%d%d", &N, &M);
    for (int i = 1; i <= N; i++)
    {
        scanf("%d", &a[i]);
        if (a[i] <= N && !pos[a[i]].size())
            pos[a[i]].push_back(0);
    }
    for (int i = 0; i < M; i++)
    {
        scanf("%d%d", &s[i], &t[i]);
        r[i] = i;
    }
    sort(r, r+M, cmp);
    for (int i = 1, j = 0; i <= N && j < M; i++)
    {
        if (a[i] <= N)
        {
            pos[a[i]].push_back(i);
            if (pos[a[i]].size() > a[i])
                Update(1, 1, N, pos[a[i]][pos[a[i]].size()-a[i]-1]+1, pos[a[i]][pos[a[i]].size()-a[i]], 1);
            if (pos[a[i]].size() > a[i]+1)
                Update(1, 1, N, pos[a[i]][pos[a[i]].size()-a[i]-2]+1, pos[a[i]][pos[a[i]].size()-a[i]-1], -1);
        }
        for (; t[r[j]] == i && j < M; j++)
            ans[r[j]] = Query(1, 1, N, s[r[j]]);
    }
    for (int i = 0; i < M; i++)
        printf("%d\n", ans[i]);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值