洛谷 P1972 HH的项链

题意:查询某一区间颜色数

思路:对于固定区间来说,颜色数只与各种颜色第一次出现的位置有关。该位置置1,该颜色其余位置置0.

          维护方法:离线,对查询按左端点排序。 查询下一个颜色的位置需要用到跳跃表next数组

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,LL> pii;
typedef pair<LL,pii> piii;
const LL maxn =500000 + 100;
const LL maxv =1000000 + 100;
const LL maxq = 500000 + 100;
const LL inf = 0x3f3f3f3f3f3f;
LL vis[maxv],a[maxn],last[maxv],b[maxn],n,ne[maxn],ans[maxq];
vector<piii> ve;
void init( LL n ){
    for( LL i = 0;i <= n;i++ ) b[i] = 0;
}
LL lowbit( LL x ){
    return x &(-x);
}
void add( LL x,LL v ){
    for( LL i = x;i <= n;i += lowbit( i ) ){
        b[i] += v;
    }
}
LL ask( LL x ){
    LL re = 0;
    while( x ){
        re += b[x];
        x -= lowbit( x );
    }
    return re;
}
int main()
{
    LL m,x,y;
    scanf("%lld",&n);
    init(n);
    for( LL i = 1;i <= n;i++ ){
        scanf("%lld",&a[i]);
    }
    scanf("%lld",&m);
    for( LL i =1;i <= m;i++ ){
        scanf("%lld%lld",&x,&y);
        ve.push_back( piii( x,pii(y,i) ) );
    }
    sort( ve.begin(),ve.end() );
    memset( vis,0,sizeof( vis ) );
    memset( last,0x3f,sizeof( last ) );
    for( LL i = n;i >= 1;i-- ){
        ne[ i ] = last[ a[i] ];
        last[ a[i] ] = i;
    }
    for( LL i = 1;i <= n;i++ ){
        if( !vis[ a[i] ] ){
            add( i,1 );
            vis[ a[i] ] = 1;
        }
    }
    LL L = 1;
    for( LL i = 0;i < ve.size();i++ ){
        LL l = ve[i].first;
        LL r = ve[i].second.first;
        LL id = ve[i].second.second;
        if( l > L ){
            for( ;L < l;L++ ){
                add( L,-1 );
                if( ne[L] < inf )
                add( ne[L],1 );
            }
        }
        ans[id] = ask( r ) - ask( L-1 );
    }
    for( LL i = 1;i <= m;i++ ){
        printf("%lld\n",ans[i]);
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值