Now Mery thinks the necklace is too long. She plans to take some continuous part of the necklace to build a new one. She wants to know each of the beautiful value of M continuous parts of the necklace. She will give you M intervals [L,R] (1<=L<=R<=N) and you must tell her F(L,R) of them.
For each case, the first line is a number N,1 <=N <=50000, indicating the number of the magic balls. The second line contains N non-negative integer numbers not greater 1000000, representing the beautiful value of the N balls. The third line has a number M, 1 <=M <=200000, meaning the nunber of the queries. Each of the next M lines contains L and R, the query.
2 6 1 2 3 4 3 5 3 1 2 3 5 2 6 6 1 1 1 2 3 5 3 1 1 2 4 3 5
3 7 14 1 3 6
题目大意就是要求给定区间的数的和,但是区间内相同的数只能加一次,所以要用到离线查询
我也是今天才了解的,学长之前讲过但我忘了,真是羞愧
离线查询大概就是两步,先弄个结构体数组储存这些查询,然后可以对这些查询进行操作,这个问题需要用到排序操作,有点贪心的感觉
将查询以右端点的大小从小到大排序(存储的时候记得保存该查询的编号),然后出现过的点因为大小<1000000,所以可以开个vis数组来保存它的上一个出现位置
然后持续更新就好
代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define ls o<<1
#define rs o<<1|1
#define lson L,mid,ls
#define rson mid+1,R,rs
#define mdzz int mid=(L+R)>>1;
int N,M;
long long tree[200005]; //不用long long 就WA的int s[50005];
int vis[1000005];
long long ans[200003];
struct node
{
int l,r,t;
bool operator <(const node &a)const
{
return a.r>r;
}
}q[200003];
void pushup(int o){
tree[o]=tree[ls]+tree[rs];
}
void update(int p,int L,int R,int o,int v){ //点修改
if(L==R){
tree[o]+=v;
return;
}
mdzz;
if(p<=mid) update(p,lson,v);
else update(p,rson,v);
pushup(o);
}
long long query(int l,int r,int L,int R,int o){//[l,r]区间询问
if(r>=R&&l<=L) return tree[o];
mdzz;
long long ans=0;
if(l<=mid)
ans+=query(l,r,lson);
if(r>mid)
ans+=query(l,r,rson);
return ans;
}
int main()
{
int T;
scanf("%d",&T);
int a,b;
while(T--)
{
memset(vis,0,sizeof vis);
memset(tree,0,sizeof tree);
scanf("%d",&N);
for(int i=1;i<=N;i++)scanf("%d",&s[i]);
scanf("%d",&M);
for(int i=1;i<=M;i++)
{
scanf("%d%d",&q[i].l,&q[i].r); //储存查询及其编号
q[i].t=i;
}
sort(q+1,q+M+1);
int p=1; //p代表当前遍历区间位置
for(int i=1;i<=M;i++)
{
while(p<=q[i].r)
{
if(vis[s[p]]) //之前有这个值,就将之前这个值出现的位置的点改为0,意思就是说在那个位置的时候不加这个值,而是在现在这个位置加
update(vis[s[p]],1,N,1,-s[p]); //不需要担心之前区间的答案会被修改,因为while循环一次是在一个查询区间内操作,若有相同值则上述处理不影响答案
vis[s[p]]=p; //若两个区间有这个相同的值,那么前一个处理的区间已经在while循环外面保存好答案了,随便改,错了算我输hhh
update(p,1,N,1,s[p]);
p++;
}
ans[q[i].t]=query(q[i].l,q[i].r,1,N,1); //这样输出的时候就是按查询顺序的
}
for(int i=1;i<=M;i++)printf("%lld\n",ans[i]);
}
return 0;
}
235



被折叠的 条评论
为什么被折叠?



