zoukankan      html  css  js  c++  java
  • Necklace HDU

    Necklace HDU - 3874 
    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.

    InputThe 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.OutputFor each query, output a line contains an integer number, representing the result of the query.Sample Input

    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

    Sample Output

    3
    7
    14
    1
    3
    6
    题意:给n个数字,代表项链每个单位的价值。在给m组查询,代表需要查询的[l,r]中的项链价值的总和;
       项链区间价值的计算方法:区间中不同数字的和,即是该区间项链价值的总和。
    做法:因为查询的区间已知,采用线段树/树状数组 + 离线查找的方法
       将需要查找的区间根据 右端点 从小到大排序。从左往右逐步把数据加入到线段树中,当达到某一查询区间的右端点时,进行一次区间和的计算。
       建立一个map数组,若某个数已经在序列中,则在最近出现的位置删除该数,这样就能保证每个数任意时刻只在线段树的中存储一次。
      (举个栗子:如样例输入中 map[1] = 1,当第二个1放入线段树的时候,需要将第一个1清除,并更新map[1] = 2,以此保证线段树中该价值仅存在一个,
       并且如果区间可以覆盖上一个map[1],那么区间必定可以覆盖现在的map[1]。)
      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<map>
      6 #include<string>
      7 #include<set>
      8 #include<stack>
      9 #include<queue>
     10 using namespace std;
     11 const int maxn = 200010;
     12 typedef long long ll;
     13 struct node{
     14     int l,r;
     15     ll sum;
     16 }tree[maxn];//建立线段树
     17 ll T,n,m;
     18 ll value[maxn],ans[maxn];// ans数组储存答案,value储存每个单位项链的价值
     19 map<ll,int> mp;// 储存价值i在数组中最近出现的位置
     20 struct node2
     21 {
     22     int l,r;
     23     int index;//题目中要求的访问的顺序
     24 }q[maxn];
     25 
     26 void build(int rt,int left,int right){
     27     tree[rt].l = left;
     28     tree[rt].r = right;
     29     tree[rt].sum = 0;// 令每个根节点的值都为零,在计算的过程中再更新节点的值
     30     if(left == right){
     31         return;
     32     }else{
     33         int mid = (left + right)>>1;
     34         build(rt<<1,left,mid);
     35         build((rt<<1)|1, mid + 1, right);
     36     }
     37 }
     38 void updata(int rt,int pos,ll val){//逐步将数据放入线段树中
     39     tree[rt].sum += val;
     40     if(tree[rt].l == tree[rt].r && tree[rt].l == pos){
     41         return;
     42     }
     43     int mid = (tree[rt].l + tree[rt].r)>>1;
     44     if(pos <= mid){
     45         updata(rt<<1,pos,val);
     46     }else{
     47         updata((rt<<1)|1,pos,val);
     48     }
     49 }
     50 ll query(int rt,int left,int right){
     51     if(tree[rt].l == left && tree[rt].r == right){
     52         return tree[rt].sum;
     53     }
     54     int mid = (tree[rt].l + tree[rt].r)>>1;
     55     if(right <= mid){
     56         return query(rt<<1,left,right);
     57     }else if(left > mid){
     58         return query((rt<<1)|1 ,left ,right);
     59     }else{
     60         return query(rt<<1,left,mid) + query((rt<<1)|1 ,mid + 1 ,right);
     61     }
     62 }
     63 
     64 bool cmp(node2 & a, node2 & b){//按照查询区间的右端点从小到大排序
     65     return a.r < b.r;
     66 }
     67 int main(){
     68     scanf("%lld",&T);
     69     while(T--){
     70         scanf("%lld",&n);
     71         build(1,1,n);
     72         mp.clear();
     73         for(int i = 1 ; i <= n ; i++){
     74             scanf("%lld",&value[i]);
     75         }
     76         scanf("%lld",&m);
     77         for(int i = 1 ; i <= m ;i++){
     78                 scanf("%d %d",&q[i].l,&q[i].r);
     79             q[i].index = i;
     80         }
     81         sort(q + 1, q + 1 + m , cmp);
     82         int id = 1;//代表目前已经计算了几次题目想要查询的区间值
     83         for(int i = 1 ; i <= n ; i++){
     84 
     85 
     86             updata(1,i,value[i]);//按顺序从左到右将数组中的数据放入线段树中
     87             if(mp[value[i]]) updata(1,mp[value[i]],-value[i]); //如果价值value[i],将之前的数据进行删除,并将线段树更新
     88             mp[value[i]] = i;// 更新value[i]最新出现的位置
     89 
     90             while(id <= m && q[id].r == i){//当计算次数小于总次数,并且线段树对应下标等于某个查询区间的右端点时,进行一次查询
     91                 ans[q[id].index] = query(1,q[id].l, q[id].r);
     92                 id++;
     93             }
     94         }
     95         for(int i = 1 ; i <= m ; i++){
     96             printf("%lld
    ",ans[i]);
     97         }
     98     }
     99     return 0;
    100 }
    线段树+离线处理做法

    一个从很久以前就开始做的梦。


      
  • 相关阅读:
    百度相关应用
    超实用js代码段一
    js模块化开发
    常见注入手法第一讲EIP寄存器注入
    异常处理第一讲(SEH),筛选器异常,以及__asm的扩展,寄存器注入简介
    32位汇编第六讲,OllyDbg逆向植物大战僵尸,快速定位阳光基址
    32位汇编第五讲,逆向实战干货,(OD)快速定位扫雷内存.
    32位汇编第四讲,干货分享,汇编注入的实现,以及快速定位调用API的数量(OD查看)
    32位汇编第三讲,RadAsm,IDE的配置和使用,以及汇编代码注入方式
    32位汇编第二讲,编写窗口程序,加载资源,响应消息,以及调用C库函数
  • 原文地址:https://www.cnblogs.com/DreamACMer/p/10840159.html
Copyright © 2011-2022 走看看