您的位置:首页 > 其它

hdu 3874 线段树 离线查询

2016-05-26 01:21 483 查看
要求一个区间所有数之和 求和时要去重 

离线查询 先把所有查询离线 然后按照右端点排序 每次保证加入后一个数的时候线段树中没有和他重复的 如果重复就把前一个删掉 这样由于之前排序过 保证不会漏解

#include<cstdio>
#include<cstring>
#include<algorithm>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
#define ll __int64
const int N=50010;
const int M=200010;
struct node
{
int l,r,i;
}q[M];
int n,a
,vis[1000010];
ll sum[N<<2],ans[M];

void pushup(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int p,int add,int l,int r,int rt)
{
if(l==r){
sum[rt]+=add;return;
}
int mid=l+r>>1;
if(p<=mid) update(p,add,lson);
else update(p,add,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)return sum[rt];
int mid=l+r>>1;
ll ans=0;
if(L<=mid) ans+=query(L,R,lson);
if(R>mid) ans+=query(L,R,rson);
return ans;
}
bool cmp(node a,node b)
{
return a.r<b.r;
}
int main()
{//freopen("C:\\Users\\Administrator\\Desktop\\input.txt","r",stdin);
int T,Q,i;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
memset(sum,0,sizeof(sum));
scanf("%d",&Q);
for(i=1;i<=Q;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].i=i;
}
sort(q+1,q+Q+1,cmp);
memset(vis,0,sizeof(vis));
int p=1;
for(i=1;i<=Q;i++){
while(p<=q[i].r){
if(vis[a[p]])update(vis[a[p]],-a[p],1,n,1);
vis[a[p]]=p;
update(p,a[p],1,n,1);
p++;
}
ans[q[i].i]=query(q[i].l,q[i].r,1,n,1);
}
for(i=1;i<=Q;i++) printf("%I64d\n",ans[i]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: