HDU

来源:互联网 发布:申请域名 编辑:程序博客网 时间:2024/05/16 09:41

Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count it once. We define the beautiful value of some interval [x,y] as F(x,y). F(x,y) is calculated as the sum of the beautiful value from the xth ball to the yth ball and the same value is ONLY COUNTED ONCE. For example, if the necklace is 1 1 1 2 3 1, we have F(1,3)=1, F(2,4)=3, F(2,6)=6.

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.
Input
The first line is T(T<=10), representing the number of test cases.
  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.
Output
For each query, output a line contains an integer number, representing the result of the query.
Sample Input
261 2 3 4 3 531 23 52 661 1 1 2 3 531 12 43 5
Sample Output
3714136

题目大意就是要求给定区间的数的和,但是区间内相同的数只能加一次,所以要用到离线查询

我也是今天才了解的,学长之前讲过但我忘了,真是羞愧

 离线查询大概就是两步,先弄个结构体数组储存这些查询,然后可以对这些查询进行操作,这个问题需要用到排序操作,有点贪心的感觉

将查询以右端点的大小从小到大排序(存储的时候记得保存该查询的编号),然后出现过的点因为大小<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;}




原创粉丝点击