BZOJ 1878 HH的项链

不能分块(显然复杂度会炸啊。。。。。)

离线+BIT。每个颜色在每个询问中只出现一次。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 50050
#define maxm 200050
#define maxc 1000500
using namespace std;
int n,a[maxn],aft[maxn],pre[maxn],regis[maxc],ans[maxm],m,p=1,t[maxn];
struct query
{
    int l,r,id;
}q[maxm];
bool cmp(query x,query y)
{
    if (x.l==y.l) return x.r<y.r;
    return x.l<y.l;
}
int lowbit(int x)
{
    return (x&(-x));
}
void add(int x,int val)
{
    for (int i=x;i<=n;i+=lowbit(i))
        t[i]+=val;
}
int ask(int x)
{
    int ret=0;
    for (int i=x;i>=1;i-=lowbit(i))
        ret+=t[i];
    return ret;
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        pre[i]=regis[a[i]];aft[pre[i]]=i;
        regis[a[i]]=i;
    }
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    for (int i=1;i<=n;i++)
    {
        if (!pre[i]) add(i,1);
        if (!aft[i]) aft[i]=n+1;
    }
    sort(q+1,q+m+1,cmp);
    for (int i=1;i<=m;i++)
    {
        for (int j=p;j<=q[i].l-1;j++)
        {
            add(j,-1);add(aft[j],1);
        }
        p=q[i].l;
        ans[q[i].id]=ask(q[i].r)-ask(q[i].l-1);
    }
    for (int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
时间: 2024-10-12 20:15:01

BZOJ 1878 HH的项链的相关文章

BZOJ 1878 HH的项链(主席树)

对于该题,离线的做法是树状数组或者线段树. 如果强制在线的话,可以用主席树做到O(mlogn). 考虑到这样一个性质,对于询问[l,r]出现的数字种数.其答案就是to[i]>r的数字数. 其中to[i]表示的是第i个数的下一个相同的数出现的下标,没有则=n+1. 很幸运这个性质是满足区间减法的,也就是说对于[1,r]和[1,l-1]的to[i]域,是可以相减得到[l,r]的to[i]域的. 于是我们可以用主席树来解决这个问题. 对于一组询问,实际上就是求[l-1,r]这颗线段树上的区间[r+1,

[bzoj] 1878 HH的项链 || 莫队

原题 给定长为 n 的一个序列,接下来 m 次询问,每次询问区间 [ l , r ] 内有多少个不同的数. 莫队: 离线\(O(n\log(n))\). 将序列分块. 以左端点所在块为第一关键字,右端点位置为第二关键字sort,然后two-points移动暴力记录即可. #include<cstdio> #include<algorithm> #include<cmath> #define N 50010 #define M 200010 using namespace

bzoj 1878 HH的项链 (树状数组+离线)

题目大意:给你一个序列,求某区间出现不同的数的个数. 貌似离线树状数组是最好的解法 先把所有询问挂在它们询问的右端点上 然后从头到尾遍历这个序列,记录这个位置的值上一次出现的位置 那么,当遍历到第i位时,如果a[i]在之前出现过,就在它上一次出现的位置-1 这个操作的意义是,第i位已经有a[i]了,那么上一次出现a[i]的位置已经失去意义 接着在这个位置+1,更新last[a[i]].差分操作用树状数组维护 然后我们遍历以这个位置为结尾的所有询问,用树状数组查前缀和,因为在a[i]相同的位置不会

【BZOJ】【1878】【SDOI2009】HH的项链

树状数组/前缀和 Orz lct1999 好神的做法... 先看下暴力的做法:对于区间[l,r],我们依次扫过去,如果这个数是第一次出现,那么我们种类数+1. 我们发现:区间中相同的几个数,只有最左边那个才对答案有贡献. 那么我们O(n)预处理一个next数组,满足a[i]=a[next[i]],且i~next[i]这一段中没有与a[i]相等的数....其实就是 i 右边第一个跟a[i]相等的值的下标啦.. 再回头看下我们的询问:对答案有贡献的数的特点是:它在整个序列中第一次出现,或者它是区间外

BZOJ 1878: [SDOI2009]HH的项链( BIT )

离线处理 , 记下询问的左右端点并排序 , 然后可以利用树状数组 , 保证查询区间时每种颜色只计算一次 ------------------------------------------------------------------------------------------------ #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define

[BZOJ 1878] [SDOI2009] HH的项链

题目链接: BZOJ - 1878 题目分析 题目的询问是某个区间内的颜色种类数,所以我们希望这个区间内的每种颜色只被计数一次,那么我们就选取询问区间内的每种颜色第一次出现的元素计数,之后再出现已经在询问区间中出现过的颜色就不再计数.考虑一种离线算法,如果我们将所有询问按照询问区间的左端点排序,那么所有询问的左端点就是不递减的,一直向右推移.开始时预处理出每个元素后面第一个与它颜色相同的元素是哪一个,并将所有出现的颜色的第一个元素加入到树状数组中.那么开始时维护的区间就是从 1 开始的.每次处理

BZOJ 1878 [SDOI2009]HH的项链 (主席树 或 莫队算法)

题目链接  HH的项链 这道题可以直接上主席树的模板 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 5e4 + 10; const int M = 3e6 + 10

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

1878: [SDOI2009]HH的项链 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 3210  Solved: 1619[Submit][Status][Discuss] Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变得越来越长.有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同 的

P1972 [SDOI2009]HH的项链

P1972 [SDOI2009]HH的项链 2017-09-18 题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的贝壳,因此,他的项链变得越来越长.有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答--因为项链实在是太长了.于是,他只好求助睿智的你,来解决这个问题. 输入输出格式 输入格式: 第一行:一个整数N,表示项链的长度. 第二行:N 个整