很不错的一道线段树题目,做了两天,终于给弄明白了。。。

看别人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;
}
posted on 2011-04-22 16:40  奋斗青春  阅读(2250)  评论(0编辑  收藏  举报