题目就不放了,占空间。
题目意思是给你一串序列,有m次询问,求区间不重复的值的和。
然后,需要用到很巧妙的处理方法。
记录一个值从左到右的出现的顺序,然后将他们串联起来,即右边一个记录前一个出现的位置,再右边一个记录这一个出现的位置,就和记录路径一样,然后我们就可以去重了。
我们对查询的区间扫描一次,每次遇到一个值,如果它之前还有一个相同的值,就把前一个相同的值删去,(用线段树的点更新实现,将前一个位置置为0)
但是,光是这样去重还是会超时的,还需要把询问都存下来,然后排一个序,这样后面的查询就可以用到之前的去重了。
由于是借鉴的别人的代码,先贴一份别人的代码,加点注释,等把代码忘了再自己敲,题目不错,不想浪费
#include <iostream>
#include <cstdio>
#include<map>
#include <cstring>
#include<vector>
#include <string>
#include<map>
#include<algorithm>
#include<cmath>
#include<set>
#define mem(a,val) memset(a,val,sizeof a)
#define lef rt<<1
#define rig rt<<1|1
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define mid (l+r)>>1
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
#define lson o<<1, l, m
#define rson o<<1|1, m+1, r
using namespace std;
typedef long long LL;
const int maxn = 50005;
const int MAX = 0x3f3f3f3f;
const int mod = 1000000007;
int t, n, m, A, B, in[maxn], last[maxn], pre[1000005]; //last记录每个点的前一个相同的点的位置,不存在记录为-1.
LL sum[maxn<<2], ans[200005];
struct C {
int l, r, num;
}a[200005];
bool cmp (C x, C y) {
return x.r < y.r;
}
void up(int o) {
sum[o] = sum[o<<1] + sum[o<<1|1];
}
void build(int o, int l, int r)
{
if(l == r) sum[o] = in[l];
else
{
int m = (l+r) >> 1;
build(lson);
build(rson);
up(o);
}
}
void update(int o, int l, int r)
{
if(l == r)
{
sum[o] = 0;
return ;
}
int m = (l+r) >> 1;
if(A <= m) update(lson);
else update(rson);
up(o);
}
LL query(int o, int l, int r)
{
if(A <= l && r <= B)
return sum[o];
int m = (l+r) >> 1;
LL res = 0;
if(A <= m) res += query(lson);
if(m < B ) res += query(rson);
return res;
}
void Ini()
{
memset(pre, -1, sizeof(pre));
memset(last, -1, sizeof(last));
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &in[i]);
if(pre[ in[i] ] != -1) //如果已经出现过
{
last[i] = pre[ in[i] ]; //记录上一次出现的位置
pre[ in[i] ] = i; //记录这一次位置
}
else pre[ in[i] ] = i;
}
}
int main()
{
scanf("%d", &t); while (t--)
{
Ini();
scanf("%d", &m);
for(int i = 1; i <= m; i++)
{
scanf("%d%d", &a[i].l, &a[i].r);
a[i].num = i;
}
sort(a+1, a+m+1, cmp); //按照 右端点排序
build(1, 1, n);
int fr = 1;
for(int i =1; i <= m; i++)
{
for(int j = fr; j <= a[i].r; j++)
if(last[j] != -1)
{
A = last[j];
update(1, 1, n); //点更新 ,值为0
}
A = a[i].l;
B = a[i].r;
ans[ a[i].num ] = query(1, 1, n); //区间查询
fr = a[i].r+1;
}
for(int i = 1; i <= m; i++)
printf("%I64d\n", ans[i]);
}
return 0;
}