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

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

      最近看了几道线段树的题都是需要离线处理数据的,正好这块比较手生,就练练了。


       这道题主要的地方就是离线处理数据,具体想法:

      ① 先把所有位置的高度都存下来,然后排序,注意保存下标;

      ② 把所有询问存下来,然后按照询问的高度进行排序,同注意保存下标;

      ③ 对于排序后的每次询问的处理:由于每个位置的高度都已经存了下来并且进行了排序,所以可以按照顺序将每个点插入到线段树的对应位置(保存的下标),并更新线段树,直到要插入的位置的高度大于这次询问的高度H;最后处理区间查询,由于刚才已经把小于等于该次查询高度的位置都已经插入到了线段树中,所以询问的结果就是查询区间中被更新过的叶子节点的个数,也就是区间求和问题

    #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 = 100000 + 5;
    const int N = 15;
    struct Node {        //每个节点的信息
        int h , pos;
        bool operator < (const Node tmp) const {
            return h < tmp.h;
        }
    } a[maxn];
    struct Section {    //每次查询的区间信息
        int L , R , H;
        int index;
        bool operator < (const Section tmp) const {
            return H < tmp.H;
        }
    } s[maxn];
    int cnt[maxn << 2] , ans[maxn];
    void PushUp(int rt)        
    {
        cnt[rt] = cnt[rt << 1] + cnt[rt << 1 | 1];
    }
    void build()
    {
        memset(cnt , 0 , sizeof(cnt)); 
    }
    void update(int p , int l , int r , int rt)
    {
        if(l == r) {
            cnt[rt]++;
            return;
        }
        int m = (l + r) >> 1;
        if(p > m)        //找到更新点的位置
            update(p , rson);
        else
            update(p , lson);
        PushUp(rt);
    }
    int query(int L , int R , int l , int r , int rt)
    {
        if(L <= l && R >= r) {
            return cnt[rt];
        }
        int m = (l + r) >> 1;
        if(L > m)
            return query(L , R , rson);
        else if(R <= m)
            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;
        for(int k = 1 ; k <= T ; k++)
        {
            build();
            printf("Case %d:
    " , k);
            scanf("%d %d" , &n , &m);
            for(i = 1 ; i <= n ; i++) {
                scanf("%d" , &a[i].h);
                a[i].pos = i;
            }
            for(i = 1 ; i <= m ; i++) {
                scanf("%d %d %d" , &s[i].L , &s[i].R , &s[i].H);
                s[i].index = i;
            }
            sort(a + 1 , a + n + 1);
            sort(s + 1 , s + m + 1);
            for(i = j = 1 ; i <= m ; i++) {        //这里就是上面的③
                while(a[j].h <= s[i].H && j <= n) {
                    update(a[j++].pos , 1 , n , 1);
                }
                ans[s[i].index] = query(s[i].L + 1 , s[i].R + 1 , 1 , n , 1);
            }
            for(i = 1 ; i <= m ; i++)
                printf("%d
    " , ans[i]);
        }
        return 0;
    }

      此题还可以用划分树来做,并且特别快,可惜我没学~

  • 相关阅读:
    poj 3304 Segments 直线 线段求交
    poj 1077 Eight 八数码 A*算法
    UESTC 1447 Area 凸包+旋转卡壳 求最大四边形面积
    ACM计算几何题目推荐(第二期)
    poj 2398 Toy Storage 叉乘
    ACM计算几何题目推荐 (第一期)
    (转载)Telnet协议详解及使用C# 用Socket 编程来实现Telnet协议
    jquery 表情编辑器
    (读书笔记)Asp.net Mvc 与WebForm 混合开发
    (转载)精简说明C#最基本的Socket编程示例
  • 原文地址:https://www.cnblogs.com/H-Vking/p/4296171.html
Copyright © 2011-2022 走看看