您的位置:首页 > 产品设计 > UI/UE

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

2018-07-31 09:09 417 查看
传送门

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

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

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

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

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

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

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

//minamoto
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 1000050
#define rint register int
using namespace std;
struct ab{
int l,r,id,ans;
} q
;
int a
,f
,n,m,last
,r;
inline int read(){
#define num ch-'0'
char ch;bool flag=0;int res;
while(!isdigit(ch=getchar()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getchar());res=res*10+num);
(flag)&&(res=-res);
#undef num
return res;
}
inline void print(int x) {
if(!x) {
putchar(48);
return;
}
if(x<0) putchar('-'),x=-x;
int l=0,wt[30];
while(x) wt[++l]=x%10,x/=10;
while(l) putchar(wt[l--]+48);
}
inline void add(int x,int y){
while(x<=n)
f[x]+=y,x+=x&(-x);
}
inline int sum(int k){
int s=0;
while(k)
s+=f[k],k-=k&(-k);
return s;
}
inline bool cmp(ab x,ab y){
return x.r<y.r;
}
inline bool cmpp(ab x,ab y){
return x.id<y.id;
}
int main(){
//freopen("testdata.in","r",stdin);
n=read();
for(rint i=1;i<=n;i++) a[i]=read();
m=read();
for(rint i=1;i<=m;i++)
q[i].l=read(),q[i].r=read(),q[i].id=i;
sort(q+1,q+1+m,cmp);
for(rint i=1;i<=m;i++){
while(r<q[i].r){
r++;if(last[a[r]]) add(last[a[r]],-1);
add(r,1),last[a[r]]=r;
}
q[i].ans=sum(q[i].r)-sum(q[i].l-1);
}
sort(q+1,q+1+m,cmpp);
for(rint i=1;i<=m;i++)
print(q[i].ans),putchar(10);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: