CF 351D - Jeff and Removing Periods(离线 + 树状数组)

题目链接:Click here~~

题意:

给一个长度为 n 的序列,Q 次询问,每次查询 [l,r] 中有多少个不同的数字,且是否存在一个数字,其出现的位置成等差数列。

解题思路:

接上篇继续刷离线查询题目。昨天想了1天,今天早上在床上想出思路了,2333333。

对于区间中不同数字的个数,可以用类似上篇的做法,c[j] 维护 [j,i] 中不同数字的个数,那么每次在位置 i 出现一个 v ,只需 [last_pos_v+1,i] 的值加 1 。

对于是否有数字的位置成等差数列,就不太好想,其实还可以用类似的方法搞。

cc[j] 维护 [j,i] 中位置成等差数列的数字的个数,每次在位置 i 出现一个 v,那么一定可以将区间 [last_pos_v+1,i] 的值加 1。

再快速找出 v 向前能延伸到的  满足位置成等差数列的  最远位置,如果这个位置比 v 上一次延伸到的位置近,那么给那段相应的区间的值减 1 就行了。

#include <vector>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int N = 1e5 + 5;

struct BIT
{
    int c[N];
    void init(){
        memset(c,0,sizeof(c));
    }
    int lowbit(int x){
        return x & -x;
    }
    void add(int loc,int val){
        while(loc < N){
            c[loc] += val;
            loc += lowbit(loc);
        }
    }
    void add(int a,int b,int val){
        if(a > b)
            return ;
        add(a,val);
        add(b+1,-val);
    }
    int sum(int loc){
        int ret = 0;
        while(loc){
            ret += c[loc];
            loc -= lowbit(loc);
        }
        return ret;
    }
}T1,T2;

struct QAQ
{
    int l,r,id;
    QAQ(){}
    QAQ(int l,int r,int i):l(l),r(r),id(i){}
    bool operator < (const QAQ& B) const{
        return r < B.r;
    }
}query[N];

int a[N],extend[N],ans[N];

vector<int> pos[N];

int main()
{
    int n,Q;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<N;i++)
        pos[i].push_back(0);
    scanf("%d",&Q);
    for(int i=0;i<Q;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        query[i] = QAQ(l,r,i);
    }
    sort(query,query+Q);
    int j = 0;
    for(int i=1;j<Q && i<=n;i++)
    {
        int v = a[i];
        pos[v].push_back(i);
        int p = (int)pos[v].size() - 1;
        T2.add(pos[v][p-1]+1,i,1);
        if(p == 1)
            extend[i] = 1;
        else
        {
            if(p == 2 || pos[v][p] - pos[v][p-1] == pos[v][p-1] - pos[v][p-2])
                extend[i] = extend[ pos[v][p-1] ];
            else
            {
                extend[i] = pos[v][p-2] + 1;
                T2.add(extend[ pos[v][p-1] ],extend[i]-1,-1);
            }
        }
        T1.add(pos[v][p-1]+1,i,1);
        while(j < Q && query[j].r == i)
        {
            ans[ query[j].id ] = T1.sum(query[j].l) + ( T2.sum(query[j].l) ? 0 : 1);
            j++;
        }
    }
    for(int i=0;i<Q;i++)
        printf("%d\n",ans[i]);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值