题解:[SDOI2009]HH的项链

刚开始暴力开数组打标记的方法水过四十分,代码是这样的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 int a[500005], num[1000005];
 6 int m, n, l, r, ans;
 7 int read(){ 
 8     int x=0,f=1; 
 9     char c=getchar(); 
10     while(c>'9'||c<'0') { 
11         if(c=='-')f=-1; 
12         c=getchar(); 
13         } 
14     while(c>='0'&&c<='9')
15         x=x*10+c-'0',c=getchar(); 
16     return x*f; 
17 } 
18 int main(){
19     n=read();
20     for(int i=1; i<=n; i++){
21         a[i]=read();
22     }
23     m=read();
24     while(m--){
25         ans=0;
26         memset(num, 0, sizeof(num));
27         l=read();
28         r=read();
29         for(int i=l; i<=r; i++){
30             if(!num[a[i]]){
31                 ans++;
32                 num[a[i]]=1;
33             }
34         }
35         printf("%d
",ans); 
36     }
37     return 0;
38 }

其实这题有好多做法,线段树,树状数组,莫队啊qwq

暴力的话可以使用莫队来做

离线的话可以使用排序加树状数组或者线段树来做

强制在线可以使用主席树来做

这是八十分的莫队(据书名号大爷说努力努力改改快读改改块的大小就卡过了qwq,然而我懒不想改……)

可能洛谷强化数据后卡了莫队两个点qwq

算是莫队入门题

先按照区间左右端点排序然后依次处理,挺好理解的

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 using namespace std;
 7 int sum, tot[1000010], ans[2000010], color[500010], pos[500010];
 8 struct node{
 9     int l, r, id;
10 }ask[2000010];
11 int n, m, qwq, L, R;
12 int read(){
13     int s=0,fh=1;char ch=getchar();
14     while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
15     while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
16     return s*fh;
17 }
18 bool cmp(node a,node b){
19     if(pos[a.l]==pos[b.l]) return a.r<b.r;
20     return a.l<b.l;
21 }
22 void del(int C){ tot[C]--; if(tot[C]==0) sum--;}
23 void add(int C){ tot[C]++; if(tot[C]==1) sum++;}
24 int main(){
25     n=read();
26     for(int i=1; i<=n; i++)    color[i]=read();
27     qwq=(int)sqrt(n);
28     m=read();
29     for(int i=1; i<=m; i++){
30         ask[i].l=read();
31         ask[i].r=read();
32         ask[i].id=i;
33     }
34     for(int i=1; i<=n; i++) pos[i]=(int)(i-1)/qwq+1;
35     sort(ask+1, ask+m+1, cmp);
36     L=1;
37     R=0;
38     memset(tot, 0, sizeof(tot));
39     for(int i=1; i<=m; i++){
40         while(L<ask[i].l){
41             del(color[L]);
42             L++;
43         }
44         while(L>ask[i].l){
45             L--;
46             add(color[L]);
47         }
48         while(R<ask[i].r){
49             R++;
50             add(color[R]);
51         }
52         while(R>ask[i].r){
53             del(color[R]);
54             R--;
55         }
56         ans[ask[i].id]=sum;
57     }
58     for(int i=1; i<=m; i++)    printf("%d
",ans[i]);
59     return 0;
60 }

接下来是能A过这道题的线段树orzzz

求和函数一个大于小于号卡了我一个小时qwq真是绝望

最近总是在疯狂RE和MLE中徘徊

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int maxn=500005;
 6 int sum[maxn*4], n, m, color[maxn], cnt, ans[maxn], last[maxn*2];
 7 struct node{
 8     int l, r, id;
 9 }ask[maxn];
10 bool cmp(node a,node b){
11     if(a.r==b.r) return a.l<b.l;
12     return a.r<b.r;
13 }
14 void pushup(int rt){
15     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
16 }
17 void update(int x, int c, int l, int r, int rt){
18     if(l==r && x==l){
19         sum[rt]=c;
20         return;
21     }
22     int mid=(l+r)>>1;
23     if(x<=mid) update(x, c, l, mid, rt<<1);
24     else   update(x, c, mid+1, r, rt<<1|1);
25     pushup(rt);
26 }
27 int query(int L, int R, int l, int r, int rt){
28     if(L<=l && r<=R) return sum[rt];
29     int mid=(l+r)>>1;
30     int ans=0;
31     if(L<=mid) ans+=query(L, R, l, mid, rt<<1);
32     if (R>mid) ans+=query(L, R, mid+1, r, rt<<1|1);
33     return ans;
34 }
35 int main(){
36     scanf("%d",&n);
37     for(int i=1; i<=n; i++)    scanf("%d",&color[i]);
38     scanf("%d",&m);
39     for(int i=1; i<=m; i++){
40         scanf("%d%d",&ask[i].l,&ask[i].r);
41         ask[i].id=i;
42     }
43     sort(ask+1, ask+m+1, cmp);
44     cnt=1;
45     for(int i=1; i<=n; i++){
46         update(i, 1, 1, n, 1);
47         if(last[color[i]]) update(last[color[i]], 0, 1, n, 1);
48         last[color[i]]=i;
49         while(ask[cnt].r==i){
50             ans[ask[cnt].id]=query(ask[cnt].l, ask[cnt].r, 1, n, 1);
51             cnt++;
52         }
53     }
54     for(int i=1; i<=m; i++)    printf("%d
",ans[i]);
55     return 0;
56 }

 然后是主席树做法,先去吃饭qwq,等会儿回来更

原文地址:https://www.cnblogs.com/Aze-qwq/p/9857158.html