http://acm.hdu.edu.cn/showproblem.php?pid=3333
树状数组+离散化+离线算法
读入所有区间,按右端点排序,每加入一个数时,如果已经加过,就在该数原来位置减去它,在新位置加上它
View Code
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 typedef __int64 LL; 6 const int N=30010,Q=100010; 7 int a[N],n,vis[N]; 8 int dz[N],nd; 9 LL c[N]; 10 struct extent 11 { 12 int u,v,p; 13 LL ans; 14 }e[Q]; 15 bool cmp1(const extent &a,const extent &b) 16 { 17 return a.v<b.v; 18 } 19 bool cmp2(const extent &a,const extent &b) 20 { 21 return a.p<b.p; 22 } 23 int bfind(int x,int *a,int l,int r) 24 { 25 while(l<r) 26 { 27 int m=(l+r)/2; 28 if(x==a[m]) return m; 29 else if(x<a[m]) r=m; 30 else l=m+1; 31 } 32 return l; 33 } 34 int lowbit(int x) 35 { 36 return x&(-x); 37 } 38 void add(int x,int p,int maxn) 39 { 40 for(int i=p;i<=maxn;i+=lowbit(i)) 41 c[i]+=x; 42 } 43 LL sum(int p) 44 { 45 LL s=0; 46 for(int i=p;i;i-=lowbit(i)) s+=c[i]; 47 return s; 48 } 49 int main() 50 { 51 int T; 52 scanf("%d",&T); 53 while(T--) 54 { 55 int n; 56 scanf("%d",&n); 57 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 58 for(int i=0;i<n;i++) dz[i]=a[i+1]; 59 sort(dz,dz+n); 60 nd=1; 61 for(int i=1;i<n;i++) 62 if(dz[i]!=dz[i-1]) dz[nd++]=dz[i]; 63 int q; 64 scanf("%d",&q); 65 for(int i=0;i<q;i++) 66 { 67 scanf("%d%d",&e[i].u,&e[i].v); 68 e[i].p=i; 69 } 70 sort(e,e+q,cmp1); 71 memset(vis,0,sizeof(vis)); 72 memset(c,0,sizeof(c)); 73 int p=0; 74 for(int i=1;i<=n;i++) 75 { 76 add(a[i],i,n); 77 int x=bfind(a[i],dz,0,nd-1); 78 if(vis[x]) add(-a[i],vis[x],n); 79 vis[x]=i; 80 while(p<q && e[p].v==i) 81 { 82 e[p].ans=sum(e[p].v)-sum(e[p].u-1); 83 p++; 84 } 85 } 86 sort(e,e+q,cmp2); 87 for(int i=0;i<q;i++) printf("%I64d\n",e[i].ans); 88 } 89 return 0; 90 }