很不错的一道线段树题目,做了两天,终于给弄明白了。。。
看别人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;
}