洛谷P1972 [SDOI2009]HH的项链——题解

题目传送

核心问题:快速求出各个区间的不同数的个数,数的值域为:[1,1e6]  (即可用O(n)数组存下)。

在线算法难以快速维护,尝试先对询问处理,采用离线算法。将询问按区间右端点r升序排列,当r确定时,一个数是否对这个询问做过贡献,只需看它在r左面的最右数是否在这个区间内,即用右端点左面的最右数来等效代替了重复且难以处理的数。设一个布尔数组f[n],表示i位置是否为当前r时某个数的最右数。可用树状数组维护其前缀和(好像nlogn的复杂度只能用树状数组,因为题目有点卡常)。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 const int N=1e6+5;
 8 
 9 int a[N],n,m,lst[N],tre[N];
10 
11 struct node{
12     int l,r,ord,ans;
13 }q[N];
14 
15 inline int read()
16 {
17     int x=0;
18     char ch=getchar();
19     while(!isdigit(ch)) 
20         ch=getchar();
21     while(isdigit(ch))
22         x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
23     return x;
24 }
25 
26 inline int cmp1(const node &u,const node &v)
27 {
28     return u.r<v.r;
29 }
30 
31 inline int cmp2(const node &u,const node &v)
32 {
33     return u.ord<v.ord;
34 }
35 
36 inline int lowbit(const int &x)
37 {
38     return x&(-x);
39 }
40 
41 inline void insert(int k,int x)
42 {
43     for(;k<=n;k+=lowbit(k))
44         tre[k]+=x;
45 }
46 
47 inline int fin(int k)
48 {
49     int ret=0;
50     for(;k>=1;k-=lowbit(k))
51         ret+=tre[k];
52     return ret;
53 }
54 
55 int main()
56 {
57     n=read();
58     for(int i=1;i<=n;++i)
59         a[i]=read();
60     m=read();
61     for(int i=1;i<=m;++i)
62         q[i].l=read(),q[i].r=read(),q[i].ord=i;
63     sort(q+1,q+m+1,cmp1);
64     int k=0;
65     for(int cnt=1;cnt<=m;++cnt)
66     {
67         while(k<q[cnt].r)
68         {
69             ++k;
70             if(lst[a[k]])
71                 insert(lst[a[k]],-1);
72             insert(k,1);
73             lst[a[k]]=k;
74         }
75         q[cnt].ans=fin(q[cnt].r)-fin(q[cnt].l-1);
76     }
77     sort(q+1,q+m+1,cmp2);
78     for(int i=1;i<=m;++i)
79         printf("%d\n",q[i].ans);
80     return 0;
81 }

 

posted @ 2020-09-25 22:04  千叶繁华  阅读(115)  评论(0编辑  收藏  举报