很不错的一道线段树题目,做了两天,终于给弄明白了。。。
看别人blog的时候,发现总是说离散化,,不明白什么意思。。。上网搜了下,其实就是一种思想的转化,,有时候我们一直在用,只不过不知道叫什么名字罢了。。。
比如对于这道题, 我们如果讨论一个数,判断它前面是否出现过,,因为0 ≤ Ai ≤ 1,000,000,000 ,很显然我们不能直接 用一个visit去判断。。
但是由于1 ≤ N ≤ 30,000 ,我们可以开一个30000的数组,然后把这些数存起来,排好序, 之后再判断一个数是否出现过的时候, 就可以用二分找到它的下标。。
对下表进行visit记录就可以了。。。
题意: 给出一个长度为N(N <= 30000)的数列,然后是一连串询问,询问数<= 100000,问给定区间内不同数字的和。
因为数字的范围较大,所以首先是对数列进行离散化,一般可以用二分或者hash,将大范围的数字映射到连续的区间。
然后一次性读入所有的区间(整数对),并且对整数对的右端点进行递增排序。这里注意,要记录下整数对读入的位置下标。。。
接下来按顺序枚举每个数字a[i],如果a[i]之前出现过,就将a[i]之前位置的值删除,然后在当前位置插入,当枚举的位置和区间对中某个位置相
等时执行询问操作。。。。
代码:
# include<stdio.h> # include<string.h> # include<stdlib.h> # define N 30005 # define M 100005 struct node{ int from,to,idx; }Q[M]; struct node1{ int left,right; __int64 num; }tree[N*4]; int a[N],tem[N],visit[N],temp[N],k; __int64 ans1,ans[M]; int cmp(const void *a,const void *b) { struct node *c=(struct node *)a; struct node *d=(struct node *)b; return c->to - d->to; } int cmp1(const void *a,const void *b) { return *(int *)a - *(int *)b; } void bulid(int l,int r,int t) { int mid; tree[t].num=0; tree[t].left=l; tree[t].right=r; if(l==r) return; mid=(l+r)/2; bulid(l,mid,2*t); bulid(mid+1,r,2*t+1); } void insert(int t,int p,int val) { int mid; if(tree[t].left==tree[t].right) {tree[t].num+=val;return;} mid=(tree[t].left+tree[t].right)/2; if(p<=mid) insert(2*t,p,val); else if(p>mid) insert(2*t+1,p,val); tree[t].num=tree[2*t].num+tree[2*t+1].num; } void Query(int t,int l,int r) { int mid; if(tree[t].left==l && tree[t].right==r) { ans1+=tree[t].num;return; } mid=(tree[t].left+tree[t].right)/2; if(r<=mid) Query(2*t,l,r); else if(l>mid) Query(2*t+1,l,r); else { Query(2*t,l,mid); Query(2*t+1,mid+1,r ); } } int is(int v) { int l,r,mid; l=1;r=k; while(l<=r) { mid=(l+r)/2; if(temp[mid]>v) r=mid-1; else if(v>temp[mid]) l=mid+1; else return mid; } } int main() { int i,j,n,ncase,id,flag,t,m; scanf("%d",&ncase); while(ncase--) { scanf("%d",&n); t=0; for(i=1;i<=n;i++) { scanf("%d",&a[i]); tem[t++]=a[i]; } qsort(tem,t,sizeof(tem[0]),cmp1); temp[1]=tem[0]; k=1; for(i=1;i<t;i++) { if(tem[i]!=tem[i-1]) { k++; temp[k]=tem[i]; } } memset(visit,0,sizeof(visit)); scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%d%d",&Q[i].from,&Q[i].to); Q[i].idx=i; } qsort(Q+1,m,sizeof(Q[1]),cmp); bulid(1,n,1); j=1; for(i=1;i<=n;i++) { id=is(a[i]); flag=visit[id]; if(flag) { insert(1,flag,-a[i]); } insert(1,i,a[i]); visit[id]=i; for(;j<=m;j++) { if(i==Q[j].to) { ans1=0; Query(1,Q[j].from,Q[j].to); ans[Q[j].idx]=ans1; } else break; } } for(i=1;i<=m;i++) { printf("%I64d\n",ans[i]); } } return 0; }