您的位置:首页 > 其它

HDU(3333)树状数组+离线

2016-01-29 14:42 369 查看
题目大意:给出一列数字,再给出一些询问,求询问的区间中,不重复的数字的总和。

思路:数据量较大,可考虑使用离线化操作,将答案存起来一并输出。先把询问的区间右端按照从小到大排序,否则查询的时候需要多次更新数组。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;
const int maxn = 33333;
struct node
{
int l, r;
int id;
bool operator < (const node &a)const
{
return r < a.r;
}
}p[maxn << 2];
long long ans[maxn << 2];//存结果
long long sum[maxn << 2];
long long a[maxn], b[maxn];
long long tail[maxn];//记录该数字上次出现的坐标
int n, q;
int lowbit(int x)
{
return x & (-x);
}
void modify(int pos, int val)
{
for(int i=pos; i<=n; i+=lowbit(i))
{
sum[i] += val;
}
/*for(int i=1; i<=n; i++)
{
cout<<"sum"<<i<<" "<<sum[i]<<endl;
}*/
}
long long query(int pos)
{
long long res = 0;
for(int i=pos; i>0; i-=lowbit(i))
{
res += sum[i];
}
return res;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
memset(sum, 0, sizeof sum);
memset(tail, 0, sizeof tail);
scanf("%d", &n);
for(int i=1; i<=n; i++)
{
scanf("%lld", &a[i]);
b[i] = a[i];
}
scanf("%d", &q);
for(int i=1; i<=q; i++)
{
scanf("%d%d", &p[i].l, &p[i].r);
p[i].id = i;
}
sort(p+1, p+1+q);
sort(b+1, b+1+n);
int tot = 1;
for(int i=1; i<=n; i++)
{
int pos = lower_bound(b+1, b+1+n, a[i]) - b;
if(!tail[pos])//判断是否之前出现过
{
modify(i, a[i]);
tail[pos] = i;
}
else
{
modify(tail[pos], a[i] * (-1));
modify(i, a[i]);
tail[pos] = i;
}
while(p[tot].r == i && tot <= q)
{
//printf("%lld %lld\n", query(i), query(p[tot].l - 1));
ans[p[tot].id] = query(i) - query(p[tot].l - 1);
tot++;
}
}
for(int i=1; i<=q; i++)
{
printf("%lld\n", ans[i]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: