BZOJ1878 [SDOI2009]HH的项链

NOIP之前写过这题,先用的分块。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=50005;
 4 int t[N+10],a[N+10];
 5 int v[1000005];
 6 int sum=0;
 7 void add(int x)
 8 {
 9     v[x]++;
10     if(v[x]==1)sum++;
11 }
12 void del(int x)
13 {
14     v[x]--;
15     if(v[x]==0)sum--;
16 }
17 int sq;
18 struct node
19 {
20     int l,r,id;
21     bool operator <(const node &b)const
22     {
23         if((l/sq)==(b.l/sq))return r<b.r;
24         return l<b.l;
25     }
26 }p[200005];
27 int ans[200005];
28 int main()
29 {
30     int n;scanf("%d",&n);
31     sq=sqrt((double)n);    
32     for(int i=1;i<=n;++i)scanf("%d",&a[i]);
33     int m;
34     scanf("%d",&m);
35     for(int i=1;i<=m;++i)
36     {
37         scanf("%d%d",&p[i].l,&p[i].r);
38         p[i].id=i;
39     }
40     sort(p+1,p+1+m);
41     int l=0,r=0;
42     for(int i=1;i<=m;++i)
43     {
44         while(r>p[i].r)del(a[r--]);
45         while(r<p[i].r)add(a[++r]);
46         while(l<p[i].l)del(a[l++]);
47         while(l>p[i].l)add(a[--l]);
48         ans[p[i].id]=sum;
49     }
50     for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
51     return 0;
52 }

又采用了树状数组,离线按右端点排序,只关心最后一个出现的位置,如果有更新的则将原来的-1将新的位置+1

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=50005;
 4 int t[N+10],a[N+10],b[N+10];
 5 int v[N+10];
 6 int lowbit(int x){
 7     return x&(-x);
 8 }
 9 void add(int x,int y)
10 {
11     for(;x<=N;x+=lowbit(x))t[x]+=y;
12 }
13 int query(int x)
14 {
15     int ans=0;for(;x;x-=lowbit(x))ans+=t[x];return ans;
16 }
17 struct node
18 {
19     int l,r,id;
20     bool operator <(const node &b)const
21     {
22         if(r==b.r)return l<b.l;
23         return r<b.r;
24     }
25 }p[200005];
26 int ans[200005];
27 int main()
28 {
29     int n;
30     scanf("%d",&n);
31     for(int i=1;i<=n;++i){scanf("%d",&a[i]);b[i]=a[i];}
32     sort(b+1,b+1+n);
33     for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+1+n,a[i])-b;
34     int m;
35     scanf("%d",&m);
36     for(int i=1;i<=m;++i)
37     {
38         scanf("%d%d",&p[i].l,&p[i].r);
39         p[i].id=i;
40     }
41     sort(p+1,p+1+m);
42     int pos=1;
43     for(int i=1;i<=m;++i)
44     {
45         while(pos<=p[i].r)
46         {
47             if(v[a[pos]])add(v[a[pos]],-1);
48             v[a[pos]]=pos;add(v[a[pos]],1);pos++;
49         }
50         ans[p[i].id]=query(p[i].r)-query(p[i].l-1);
51     }
52     for(int i=1;i<=m;++i)printf("%d\n",ans[i]);
53     return 0;
54 }

现在我又学了主席树,我们只要对于last(上一次的位置)建主席树,然后查询0~l-1这个区间出现的个数即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=1e6+10;
 4 struct node
 5 {
 6     int l,r,s;
 7 }t[N<<2];
 8 int n,m,cnt,last[N],pos[N],rt[N];
 9 void change(int &x,int l,int r,int pos)
10 {
11     t[++cnt]=t[x];x=cnt;
12     if(l==r){t[x].s++;return;}
13     int mid=l+r>>1;
14     if(pos<=mid)change(t[x].l,l,mid,pos);
15     else change(t[x].r,mid+1,r,pos);
16     t[x].s=t[t[x].l].s+t[t[x].r].s;
17     return;
18 }
19 int query(int x,int y,int l,int r,int L,int R)
20 {
21     if(l==L&&r==R)return t[y].s-t[x].s;
22     int mid=l+r>>1;
23     if(mid>=R)return query(t[x].l,t[y].l,l,mid,L,R);
24     else if(mid<L)return query(t[x].r,t[y].r,mid+1,r,L,R);
25     return query(t[x].l,t[y].l,l,mid,L,mid)+query(t[x].r,t[y].r,mid+1,r,mid+1,R);
26 }
27 int main()
28 {
29     scanf("%d",&n);int x,l,r;
30     for(int i=1;i<=n;++i)
31     {
32         scanf("%d",&x);
33         last[i]=pos[x];
34         pos[x]=i;
35     }
36     for(int i=1;i<=n;++i)rt[i]=rt[i-1],change(rt[i],0,n,last[i]);
37     scanf("%d",&m);
38     for(int i=1;i<=m;++i)
39     {
40         scanf("%d%d",&l,&r);
41         printf("%d\n",query(rt[l-1],rt[r],0,n,0,l-1));
42     }
43     return 0;
44 }

 

posted @ 2018-01-23 18:42  大奕哥&VANE  阅读(147)  评论(0编辑  收藏  举报