bzoj1878: [SDOI2009]HH的项链(树状数组+离线处理)

题目传送门
真是毒瘤题。

解法:
好恶心树状数组还有这个功能?!
区间种数也可以用树状数组维护?!
果断%一发题解。
看了半天发现:
用树状数组维护前缀和。
last[i]表示i这个位置的颜色上一个出现的位置是哪里。
那么我们在last[i]+1这个位置+1
在i+1这个位置-1。
那么我们在统计前缀和的时候每种颜色不论出现多少次贡献都为1。
每一段的答案等于求1~l的和。
为什么?
比如一个颜色在l之前有出现过,那么如果在l之后也出现了这种颜色的话,这种颜色一定是有1个贡献的。
如果一个颜色在l之前没有出现过,那么如果在l之后出现过了的话那么这种颜色的last=0,所以last+1也就是在1位置有+1所以颜色总类会+1。
自己yy吧这东西真毒瘤。

代码实现:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
struct node {
    int l,r,s;
}a[210000];
bool cmp(node n1,node n2) {
    return n1.r<n2.r;
}
int s[51000];
int lowbit(int x) {
    return x&-x;
}
int n;
void change(int x,int k) {
    while(x<=n) {
        s[x]+=k;
        x+=lowbit(x);
    }
}
int get_sum(int x) {
    int ans=0;
    while(x>0) {
        ans+=s[x];
        x-=lowbit(x);
    }
    return ans;
}
int last[1110000],sh[1110000];
int ans[210000];
int main() {
    int m;scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        int x;scanf("%d",&x);
        last[i]=sh[x];
        sh[x]=i;
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&a[i].l,&a[i].r);
        a[i].s=i;
    }
    sort(a+1,a+1+m,cmp);
    int now=0;
    for(int i=1;i<=m;i++) {
        while(now<a[i].r) {
            now++;
            change(last[now]+1,1);
            if(now!=n)
                change(now+1,-1);
        }
        ans[a[i].s]=get_sum(a[i].l);
    }
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值