题目大意:
多组测试数据,给你一串数(50000个),每个数最大1,000,000,然后询问最多200,000次区间和。
但是有一个很麻烦的地方就是,一个区间里面,相同的数只能计算一次。
分析:
看似有相同的数只是一个很小的细节,但是这应该才是这道题的关键。
现在急于解决的一个问题就是,怎样让这些相同的数不被重复计算,比较感性的想法就是,这些数我只存一个,也就是第一个,后面再出现我就不存了。但是这样询问区间的时候必定会出现问题。
我的解决办法就是,把区间按照起点坐标从小到大排序,起点坐标相同的两个区间的先后顺序无所谓。按顺序依次访问。在访问区间 [ a , b ] 的时候就删掉 a 左面的点, 这个删掉的意思是,把 a 左面出现多次但是只记录了第一次的数右移到 a 的右边,也就是他第 k(k>1)次出现但是当时没有记录下来的位置。用哈希表实现。要是真的要算最差的时间复杂度,做哈希表就要50000*50001/2就该超时了,但是那样的数据实在是太bt了,所以我决定先打出来试一下。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 50500
#define maxm 200500
#define maxx 1005000
using namespace std;
long long int tree[maxn];
int n,m;
int my_hash[maxx];
int my_next[maxn];
int a[maxn];
long long int ans[maxm];
struct interval
{
int s;
int e;
int w;
}inv[maxm];
int lowbit(int x)
{
return x&(-x);
}
void add(int i,int x)//给i位置加上x
{
while(i<maxn)
{
tree[i]+=x;
i+=lowbit(i);
}
}
long long int sum(int x)
{
if(x==0)return 0;
long long int s=0;
while(x>0)
{
s+=tree[x];
x-=lowbit(x);
}
return s;
}
bool my_cmp(interval a,interval b)
{
return a.s<b.s;
}
int main()
{
int test;
cin>>test;
while(test--)
{
memset(my_hash,0,sizeof(my_hash));
memset(my_next,0,sizeof(my_next));
memset(tree,0,sizeof(tree));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(my_hash[a[i]]!=0)
{
int l=my_hash[a[i]];
while(my_next[l]!=0)
{
l=my_next[l];
}
my_next[l]=i;
}
else
{
my_hash[a[i]]=i;
add(i,a[i]);
}
}
cin>>m;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&inv[i].s,&inv[i].e);
inv[i].w=i;
}
sort(inv+1,inv+m+1,my_cmp);
int t=1;
for(int i=1;i<=m;i++)
{
for(;t<inv[i].s;t++)
{
if(my_next[my_hash[a[t]]]!=0)
{
add(my_hash[a[t]],-a[t]);
my_hash[a[t]]=my_next[my_hash[a[t]]];
add(my_hash[a[t]],a[t]);
}
}
ans[inv[i].w]=sum(inv[i].e)-sum(inv[i].s-1);
}
for(int i=1;i<=m;i++)
{
printf("%lld\n",ans[i]);
}
}
}
后记:
果然数据没有那么bt,很快ac了。
注意:
1.tree数组等要用 long long int 。
2.输入输出用 cin,cout 就超时了。
最后在重新总结一遍思路就是,按照某一特定顺序查询区间,同时一边查找,一边按照特定的规则增加数据到树状数组里面了,这样就可以使得按照顺序查询的区间得到的答案都是正确的,既重复的数字只计算了一次的区间和。