SPOJ 3267 DQUERY(离线+树状数组)
Posted bztminamoto
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于SPOJ 3267 DQUERY(离线+树状数组)的主要内容,如果未能解决你的问题,请参考以下文章
[SPOJ DQUERY] D-query(树状数组,离线)
SPOJ - DQUERY: D-query 离线处理 + 树状数组