Turing Tree
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5580 Accepted Submission(s): 1992
Now given a sequence of N numbers A1, A2, ..., AN and a number of Queries(i, j) (1≤i≤j≤N). For each Query(i, j), you are to caculate the sum of distinct values in the subsequence Ai, Ai+1, ..., Aj.
For each case, the input format will be like this:
* Line 1: N (1 ≤ N ≤ 30,000).
* Line 2: N integers A1, A2, ..., AN (0 ≤ Ai ≤ 1,000,000,000).
* Line 3: Q (1 ≤ Q ≤ 100,000), the number of Queries.
* Next Q lines: each line contains 2 integers i, j representing a Query (1 ≤ i ≤ j ≤ N).
2 3 1 1 4 2 1 2 2 3 5 1 1 2 1 3 3 1 5 2 4 3 5
1 5 6 3 6
题意:
和前面说的Necklace一样,只不过数据大了。需要进行离散化操作。
思路:
树状数组离散化这里运用stl对数据进行离散,其实离散的目的就是为了后面方便记录这个数字是否出现过,如果不离散,数据非常大,那么数组就会发生越界。
关于lower_bound()函数的总结:
函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置
举例如下:
一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标
则
pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。
pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。
pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。
所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~
返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置代码:
#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iomanip>
#include<queue>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
int n,m;
ll tree[30005],ans[100005]; //树状数组和记录结果的数组
int a[30005],vis[30005],b[30005],pos[30005];//vis表示是否出现过,
struct node{
int s,e,id;
bool operator <(const node& b) const //排序
{
return e<b.e||(e==b.e&&s<b.s);
}
}p[100005];
int lowbit(int i)
{
return i&(-i);
}
void add(int i,int v)
{
while(i<=n)
{
tree[i]+=v;
i+=lowbit(i);
}
}
ll sum(int i)
{
ll res=0;
while(i>0)
{
res+=tree[i];
i-=lowbit(i);
}
return res;
}
int main()
{
int i,T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
memset(tree,0,sizeof(tree));
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&p[i].s,&p[i].e);
p[i].id=i;
}
sort(p+1,p+m+1);
sort(b+1,b+n+1);
for(i=1;i<=n;i++)
{
pos[i]=lower_bound(b+1,b+n+1,a[i])-b;
}
int it=1;
for(i=1;i<=m;i++)
{
while(it<=p[i].e) //去重,因为对右区间由小到大排序了。所以去重不会对后面产生影响
{
if(vis[pos[it]]!=0)
{
add(vis[pos[it]],-a[it]); //离散的作用体现在这
}
vis[pos[it]]=it;
add(it,a[it]);
it++;
}
ans[p[i].id]=sum(p[i].e)-sum(p[i].s-1);
}
for(i=1;i<=m;i++)
{
printf("%I64d\n",ans[i]);
}
}
return 0;
}