题目大意:给出n个序列,和m个查询每个查询为1个区间[l,r],要求对于每个查询,输出这个区间内不重复的数的和
(比如说区间内的数为 3 4 4 5,和就为12,因为对于相同的数只会统计一次)
反正这道题我第一眼看到完全是蒙的。。。后来问lz神,讲了一会才把我讲懂。。。我太弱了啊
这道题是这么做的。。。在线操作不行,考虑离线,先读入所有查询区间,然后对于值相同的数,把相邻的两个数的位置作为一个区间的左右端点。。。把查询区间与这些区间(就叫做原区间吧)一起按右端点从小到大排个序(如果右端点相同的话。。原区间排前面)
建立一颗初始值全为0的线段树。然后扫描排序后的区间,遇到一个原区间,就在他左端点的位置,加上这个原区间原来所在端点对应的值,遇到一个查询区间(左右端点为l,r),这个区间的答案就是:sum[r] - sum[l-1] - 线段树中的l~r区间和。(sum为前缀和。。。可以预处理出来)
最后再按照区间原序输出(至于这个怎么做到应该自己想一下就能搞定吧。。。)
这样为什么是对的呢?如果查询区间包含了一个 值为x的区间。。。那么通过前缀和算出来的值就多加了一个x。所以要减去x。。。如果包含了2个值为x的区间的话,那就多了两个x。。(这两个区间一定是挨着的)。。。所以线段树里面存的就是多加了的值,要减去。
至于怎么把原区间弄出来。。。用map[x]记录上一个x的位置。。。于是当扫到一个x,就有map[x]~现在位置的一个区间,然后更新map[x],参看代码
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
int n,m,t;
map<int,int>pre;
struct T
{
int l,r;
long long sum;
}tree[50000*4+10];
struct E
{
int l,r;
int flag;//flag==0:ori
int num;
bool operator <(const E &b)const
{
if(r!=b.r)return r<b.r;
else return flag<b.flag;
}
}e[300000+10];
int s[200000+10];
long long sum[50000+10];
long long ans[200000+10];
void build(int id,int l,int r)
{
tree[id].l=l;tree[id].r=r;
if(l==r)
{
tree[id].sum=0;
return;
}
int mid=(l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}
void insert(int id,int pos,int val)
{
if(tree[id].l==tree[id].r)
{
tree[id].sum+=val;
}
else
{
int mid=(tree[id].l+tree[id].r)>>1;
if(pos<=mid)insert(id<<1,pos,val);
else insert(id<<1|1,pos,val);
tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;
}
}
long long query(int id,int l,int r)
{
if(l<=tree[id].l&&tree[id].r<=r)
{
return tree[id].sum;
}
else
{
int mid=(tree[id].l+tree[id].r)>>1;
long long ret=0;
if(l<=mid)ret+=query(id<<1,l,r);
if(r>mid)ret+=query(id<<1|1,l,r);
return ret;
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
pre.clear();
int tail=0;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
sum[i]=sum[i-1]+x;
if(pre.count(x))
{
e[tail].l=pre[x];
e[tail].r=i;
e[tail].flag=0;
e[tail].num=x;
tail++;
}
pre[x]=i;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int l,r;
scanf("%d%d",&l,&r);
e[tail].l=l;
e[tail].r=r;
e[tail].flag=i;
tail++;
}
sort(e,e+tail);
build(1,1,n);
for(int i=0;i<tail;i++)
{
if(!e[i].flag)
{
insert(1,e[i].l,e[i].num);
}
else
{
ans[e[i].flag]=sum[e[i].r]-sum[e[i].l-1]-query(1,e[i].l,e[i].r);
}
}
for(int i=1;i<=m;i++)
{
printf("%I64d\n",ans[i]);
}
}
return 0;
}