洛谷 P1972 [SDOI2009]HH的项链(树状数组,离线)

传送门

解题思路

因为是求区间的不同种类数,所以我们用树状数组(貌似并没有什么直接联系)

(...表示到)

还是和原来一样,用s[i]来表示a[i-lowbit(i)]...a[i]的种类数。

因为有一个类似于去重的操作,所以就有一个数组记录一下is[i]表示编号为i的贝壳上一次出现的地方,每一次更新结果时s[is[i]]--;s[i]++;is[i]=i。

但是我们想,假设询问的一个区间为a...b,下一个区间为a...b-5,并且x这种贝壳在b-3,b-7都出现过(a<b-7<b-5<b-3<b),那么我们在询问a...b时使s[b-7]--;然后再询问a...b-5时就会导致答案出错(少算了一个)。(解释的不太清楚,感性理解一下)

所以这里我们用到一个操作——离线,所谓离线,就是一次性把问题全部输入,根据一定的顺序排序(便于解题),保存好答案后再根据原顺序输出。

怎样用程序实现离线呢?我们可以用结构体来存储数据,每一个结构体变量中有一个保存数值,另一个保存序号,全部读入后按照数值的关键字sort一遍,输出答案前按照关键字序号再sort一遍,这样就达到了目的。

比如说这一道题:

 1 struct ques {
 2     int l,r,ans,id;
 3 } q[maxn];
 4 bool cmp1(ques a,ques b) {
 5     return a.r<b.r;
 6 }
 7 bool cmp2(ques a,ques b) {
 8     return a.id<b.id;
 9 }
10 int main() {
11     //读入数据
12     sort(q+1,q+m+1,cmp1);//第一遍sort
13     //求出答案
14     sort(q+1,q+m+1,cmp2);//第二遍sort
15     //输出答案
16     return 0;
17 }

AC代码

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 using namespace std;
 5 const int maxn=500005;
 6 int s[maxn],n,a[maxn],m;
 7 int is[maxn*2];
 8 inline int lowbit(int x) {
 9     return x&(-x);
10 }
11 void insert(int id,int k) {
12     for(int i=id; i<=n; i+=lowbit(i)) {
13         s[i]+=k;
14     }
15 }
16 int query(int id) {
17     int res=0;
18     for(int i=id; i>0; i-=lowbit(i)) {
19         res+=s[i];
20     }
21     return res;
22 }
23 struct ques {
24     int l,r,ans,id;
25 } q[maxn];
26 bool cmp1(ques a,ques b) {
27     return a.r<b.r;
28 }
29 bool cmp2(ques a,ques b) {
30     return a.id<b.id;
31 }
32 int main() {
33     cin>>n;
34     int cnt=1;
35     for(int i=1; i<=n; i++) {
36         scanf("%d",&a[i]);
37     }
38     cin>>m;
39     for(int i=1; i<=m; i++) {
40         scanf("%d%d",&q[i].l,&q[i].r);
41         q[i].id=i;
42     }
43     sort(q+1,q+m+1,cmp1);
44     for(int i=1; i<=n; i++) {
45         if(is[a[i]]) {
46             insert(is[a[i]],-1);
47         }
48         insert(i,1);
49         is[a[i]]=i;
50         while(q[cnt].r==i&&cnt<=m) {
51             q[cnt].ans=query(q[cnt].r)-query(q[cnt].l-1);
52             cnt++;
53         }
54     }
55     sort(q+1,q+m+1,cmp2);
56     for(int i=1; i<=m; i++) {
57         printf("%d\n",q[i].ans);
58     }
59     return 0;
60 }

猜你喜欢

转载自www.cnblogs.com/yinyuqin/p/11110794.html