zoukankan      html  css  js  c++  java
  • HDU3874 线段树 + 离线处理

      题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3874 , 线段树(或树状数组) + 离线处理

      下午做了第一道离线处理的题目(HDU4417),多少有点感觉,顺便就把这道题也给做了。


      这道题就是要求某个区间内不重复数的和,自己在网上百度后参考别人的方法才AC的。参考来源:http://www.cnblogs.com/gj-Acit/p/3249827.html

      这道题还是需要先离线处理数据,具体方法:

      ① 先用线段树把树给建立起来;

      ② 先把所有要查询的区间存起来,按照区间的右边界的大小从小到大排序,注意保存下标;

        ③ 对于排序后的每次询问要这样处理:把上次询问区间的右边界到当前询问的右边界中的这些数字进行处理,如果这些数字在之前出现过,则把之前出现的这个数字给删掉(置0即可),然后单点更新线段树;然后查询的话用线段树进行区间求和即可。

      我参考的方法中是这样处理的,即用一个数组vis[]存储数字a[i]第一次出现的位置,后来扫描的时候如果发现 vis[a[i]] != i ,即说明该数字之前出现过。

      最后注意这里用int储存结果会爆掉的,所以要用__int64.

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    #include <string>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    #define LL __int64
    #define eps 1e-8
    #define lson l , m , rt << 1
    #define rson m + 1 , r , rt << 1 | 1
    const int MOD = 10000007; 
    const int maxn = 50000 + 5;
    const int N = 1000000 + 5;
    LL sum[maxn << 2] , ans[maxn << 2];        //sum[]存线段树,ans[]存结果
    int vis[N] , a[maxn];    //vis[]第一次出现的位置,a[]存储叶子节点信息
    struct Section {        //区间
        int L , R;
        int index;
        bool operator < (const Section tmp) const {
            return R < tmp.R;
        }
    } s[maxn << 2];        
    void PushUp(int rt)
    {
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    void build()
    {
        memset(sum , 0 , sizeof(sum));
        memset(vis , 0 , sizeof(vis));
    }
    void update(int pos , int x , int l , int r , int rt)
    {
        if(l == r) {
            sum[rt] = x;
            return;
        }
        int m = (l + r) >> 1;
        if(pos > m)
            update(pos , x , rson);
        else
            update(pos , x , lson);
        PushUp(rt);
    }
    LL query(int L , int R , int l , int r , int rt)
    {
        if(L <= l && R >= r) {
            return sum[rt];
        }
        int m = (l + r) >> 1;
        if(m < L)
            return query(L , R , rson);
        else if(m >= R)
            return query(L , R , lson);
        else
            return query(L , R , lson) + query(L , R , rson);
    }
    int main()
    {
        int T , i , j , n , m;
        cin >> T;
        while(T--)
        {
            build();
            scanf("%d" , &n);
            for(i = 1 ; i <= n ; i++) {
                scanf("%d" , &a[i]);
                if(!vis[a[i]])        //a[i]第一次出现的位置
                    vis[a[i]] = i;
                update(i , a[i] , 1 , n , 1);    //实际是在这里建的树
            }
            scanf("%d" , &m);
            for(i = 1 ; i <= m ; i++) {
                scanf("%d %d" , &s[i].L , &s[i].R);
                s[i].index = i;
            }
            sort(s + 1 , s + m + 1);
            for(i = 1 , s[0].R = 1; i <= m ; i++) {        //此为步骤③
                for(j = s[i - 1].R ; j <= s[i].R ; j++) {
                    if(vis[a[j]] != j) {
                        int tmp = vis[a[j]];
                        update(tmp , 0 , 1 , n , 1);    //删掉之前出现的该数字
                        vis[a[j]] = j;                    //删掉后再换位置
                    }
                }
                ans[s[i].index] = query(s[i].L , s[i].R , 1 , n , 1);
            }
            for(i = 1 ; i <= m ; i++)
                printf("%I64d
    " , ans[i]);
        }
        return 0;
    }
  • 相关阅读:
    配置python库源为清华源
    ubuntu下安装使用jupyter
    《在下雪天气里和女朋友在一起就会有种很特别的氛围,我很喜欢》梗图
    ubuntu安装cuda、cudnn和nvidia-docker
    jreg视频内容整理
    【北邮人论坛帖子备份】给考公同学的建议。如今我流的泪都是当年脑子进的水
    拉取docker容器后启动容器的脚本
    多个git账户ssh密钥配置
    【北邮人论坛帖子备份】【FAQ】给今年国企求职学弟学妹的一点建议
    nui-app记录不明白的属性
  • 原文地址:https://www.cnblogs.com/H-Vking/p/4296296.html
Copyright © 2011-2022 走看看