题目给定一个序列,让后查询m个区间,输出区间内数的和,重复的不计算多次。
想了半天也没想出来怎么在线维护这样的线段树,那就考虑一下离线怎么做。如果把区间按右端点排序,那么每次查询 [ l , r ] 的时候,如果都能保证 [ 1 , r ] 内重复数字的下标都在最右边,那这样即可避免重复了,而且还能保证每次查询的准确性。也就是说每次询问,看一下 [ 1 , r ] 是否已经确定,如果还没确定的话就需要遍历到 r ,这样就保证了每次 [ 1 , r ] 区间内没有重复的数字,且下标都只保留最右边。
最好是用树状数组写,线段树在洛谷能被卡掉好几个点,当初想用在线做所以敲了个线段树,不想改了 。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=30010,M=100010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;
int n;
int a[N],b[N];
LL ans[M];
struct query
{
int l,r;
bool operator < (const query &w) const
{
return r<w.r;
}
int id;
}q[M];
struct Node
{
int l,r;
LL sum;
}tr[N<<2];
void pushup(int u)
{
tr[u].sum=tr[L].sum+tr[R].sum;
}
void build(int u,int l,int r)
{
tr[u]={l,r,0};
if(l==r)
{
tr[u].sum=0;
return;
}
build(L,l,Mid),build(R,Mid+1,r);
pushup(u);
}
LL query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].sum;
LL ans=0;
if(l<=Mid) ans+=query(L,l,r);
if(r>Mid) ans+=query(R,l,r);
pushup(u);
return ans;
}
void modify(int u,int l,int r,LL c)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].sum+=c;
return;
}
if(l<=Mid) modify(L,l,r,c);
else modify(R,l,r,c);
pushup(u);
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
int t; cin>>t;
while(t--)
{
int tot=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
int m; scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q+1,q+1+m);
build(1,1,n);
map<LL,int>mp; int t=1;
for(int i=1;i<=m;i++)
{
int l=q[i].l,r=q[i].r;
while(t<=r)
{
if(!mp.count(a[t]))
modify(1,t,t,a[t]);
else
{
modify(1,mp[a[t]],mp[a[t]],-a[t]);
modify(1,t,t,a[t]);
}
mp[a[t]]=t; t++;
}
ans[q[i].id]=query(1,l,r);
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
}
return 0;
}
/*
*/