SDOI2009 HH的项链

传送门

这道题原来是可以用莫队暴力过掉的……但是数据加强之后500000万的范围使得nsqrtn的算法无法通过,那我们只能用log的方法,也就是树状数组。

本题要求我们统计的是贝壳的个数,我们唯一的困难在于如何判断重复元素。考虑这样一个事情,对于一些右端点相同的区间,我们在统计这些区间之内的情况的时候,重复的元素我们只关心它出现在最右边的一个。

举例子,比如区间1,2,3,2,4 对于这个长度为5的区间,我们对于每个诸如[l,5]的询问,第一个2完全不需要被考虑,因为它已经被第二个2完全覆盖了。(左端点靠前的,2可以被后面的计算,靠后的就完全没前面事了

 

所以我们可以把所有的区间按右端点排序,之后离线处理。对于每个右端点,把在其之前的都在树状数组中加上,而已经出现过的元素,就在原来的位置先删除,之后再在当前位置添加。统计的时候直接计算两端和相减即可。

 

听起来是不是很简单……?

 

看一下代码。

 

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
const int M = 1005;
const int N = 1000005;
const int INF = 1e9;
double eps = 1e-7;
typedef long long ll;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
    }
    return ans * op;
}

struct ask
{
    int l,r,pos;
    bool operator < (const ask &g) const
    {
        if(r == g.r) return l < g.l;
        return r < g.r;
    }
}a[N];
struct answer
{
    int val,p;
    bool operator < (const answer &g) const
    {
        return p < g.p;
    }
}ans[N];
int n,m,shell[N],cur = 1,c[N],loc[N];
bool vis[N];
int lowbit(int x)
{
    return x & (-x);
}
void add(int x,int v)
{
    while(x <= n)
    {    
        c[x] += v;
        x += lowbit(x);
    }
}
int query(int x)
{
    int sum = 0;
    while(x)
    {
        sum += c[x];
        x -= lowbit(x);
    }
    return sum;
}
int main()
{
    n = read();
    rep(i,1,n) shell[i] = read();
    m = read();
    rep(i,1,m) a[i].l = read(),a[i].r = read(),a[i].pos = i;
    sort(a+1,a+1+m);
    rep(i,1,m)
    {
        while(cur <= a[i].r)//所有在前面的都要统计
        {
            if(!vis[shell[cur]]) add(cur,1),loc[shell[cur]] = cur,vis[shell[cur]] = 1;//这个元素没出现过
            else add(loc[shell[cur]],-1),add(cur,1),loc[shell[cur]] = cur;//元素出现过
            cur++;
        }
        ans[i].val = query(a[i].r) - query(a[i].l-1),ans[i].p = a[i].pos;//计算出现次数
    }
    sort(ans+1,ans+1+m);//注意要重新按照出现的次序排序
    rep(i,1,m) printf("%d\n",ans[i].val);
    return 0;
}

 

posted @ 2018-09-01 22:24  CaptainLi  阅读(140)  评论(0编辑  收藏  举报