SPOJ 3267 DQUERY(离线+树状数组)

传送门

 

话说这好像HH的项链啊……

然后就说一说上次看到的一位大佬很厉害的办法吧

对于所有$r$相等的询问,需要统计有多少个不同的数,那么对于同一个数字,我们只需要关心它最右边的那一个

比如$1,2,3,4,1,2$,对于所有$r=5$的询问,我们不用去管第一个$1$因为它一定可以被第五个$1$代替

同理,对于所有$r=6$的询问,我们也不需要去管第二个$2$

然后我们可以将所有询问离线,按$r$升序排序

每一次进行扫描,如果一个数没有出现过,就在树状数组中加入,否则就将它上一次出现的位置的那一个删除,再将它加入

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #define N 1000050
 6 #define rint register int
 7 using namespace std;
 8 struct ab{
 9     int l,r,id,ans;
10 } q[N];
11 int a[N],f[N],n,m,last[N],r;
12 inline int read(){
13     #define num ch-'0'
14     char ch;bool flag=0;int res;
15     while(!isdigit(ch=getchar()))
16     (ch=='-')&&(flag=true);
17     for(res=num;isdigit(ch=getchar());res=res*10+num);
18     (flag)&&(res=-res);
19     #undef num
20     return res;
21 }
22 inline void print(int x) {
23     if(!x) {
24         putchar(48);
25         return;
26     }
27     if(x<0) putchar('-'),x=-x;
28     int l=0,wt[30];
29     while(x) wt[++l]=x%10,x/=10;
30     while(l) putchar(wt[l--]+48);
31 }
32 inline void add(int x,int y){
33     while(x<=n)
34     f[x]+=y,x+=x&(-x);
35 }
36 inline int sum(int k){
37     int s=0;
38     while(k)
39     s+=f[k],k-=k&(-k);
40     return s;
41 }
42 inline bool cmp(ab x,ab y){
43     return x.r<y.r;
44 }
45 inline bool cmpp(ab x,ab y){
46     return x.id<y.id;
47 }
48 int main(){
49     //freopen("testdata.in","r",stdin);
50     n=read();
51     for(rint i=1;i<=n;i++) a[i]=read();
52     m=read();
53     for(rint i=1;i<=m;i++)
54     q[i].l=read(),q[i].r=read(),q[i].id=i;
55     sort(q+1,q+1+m,cmp);
56     for(rint i=1;i<=m;i++){
57         while(r<q[i].r){
58             r++;if(last[a[r]]) add(last[a[r]],-1);
59             add(r,1),last[a[r]]=r;
60         }
61         q[i].ans=sum(q[i].r)-sum(q[i].l-1);
62     }
63     sort(q+1,q+1+m,cmpp);
64     for(rint i=1;i<=m;i++)
65     print(q[i].ans),putchar(10);
66     return 0;
67 }

 

posted @ 2018-07-31 09:09  bztMinamoto  阅读(234)  评论(0编辑  收藏  举报
Live2D