zoukankan      html  css  js  c++  java
  • Little Elephant and Array 线段树

    题目:http://codeforces.com/problemset/problem/220/B

    题意

    给定一组数据,多次询问区间内某数字出现次数与该数字数值相同的数的个数

    思路

    一看到区间查询,就会想到线段树,有木有!

    单点或区间的修改、查询等可是线段树的强项嘞√

    而我们今天的线段树类型为: 离线处理、区间更新、单点查询

    给定一个数字序列,线段树每个节点所要记录的状态是 :从此处以及到正在处理的元素处满足题意的ans

    上面一句话什么意思嘞

    我们做的是 边建树,边查询,当对应状态的线段树建立完成,即可得到答案。

    比如  一段序列 : 8 3 4 4 1 3 3 2 2

    当我们处理到第7个数的时候,状态分别为 2 2 1 1 1 0 0

    以上是线段树的属性介绍,下面就是具体的操作流程

    我们需要知道不同数字所出现的所有的位置,用一个二维空间pos存储该信息,比如上面pos[3]存储的数据即为 2、6、7

    首先,将所有的询问区间按照右端点进行非递减排序

    我们从序列的第一数字开始,建树。

    当num数字第 t 次出现时候,如果,t >= num的时候,我们将【1,num第一次出现的位置】的值+1,

                                                 如果,t > num  的时候,我们将【1,num第一次出现的位置】的值-1

    以此来保证线段树每个节点所要记录的状态

    如此做,当处理到第i个数字的时候,查看是否到达当前正在处理的区间的右端点,

    如果到达,那么,当前处理区间的左端点的节点状态即为所求

    为什么呢,因为我们是一个一个将序列中的元素放入树中的,而我们的询问区间是按照右端点非递减排序的,那么就保证了,处理到第i个序列元素的时候,到达了询问区间右端点,而根据树节点所记录的状态可知,即为答案,而此时的状态,并没有把i处之后的序列元素作考虑,所以,按照区间右端点递增,且序列元素逐一入树,边建树边查询,树节点所记录的状态定为答案。

    为了方便,我们将每种数字第一次出现的位置均赋值为0

    代码如下:

    #include<iostream>
    #include<algorithm>  
    #include<vector>  
    using namespace std;
    
    const int MAXN = 100005;
    int N, M, list[MAXN], s[MAXN], t[MAXN], rank_[MAXN], result[MAXN];
    int Tr[MAXN << 2], mark[MAXN << 2];
    vector<int> pos[MAXN];
    
    inline bool cmp(const int a, const int b)
    {
        return t[a] < t[b];
    }
    
    void PushDown(int idx);            //向下更新       沿para向下更新子树
    
    void Update(int idx, int L, int R, int l, int r, int c);     //区间更新    para1:当前结点的树下标
    
    int Query(int idx, int L, int R, int x);                     //单点询问
    
    int main()
    {
        cin >> N >> M;
        for (int i = 1; i <= N; i++)
        {
            cin >> list[i];
            if (list[i] <= N && !pos[list[i]].size())
                pos[list[i]].push_back(0);
        }
        for (int i = 0; i < M; i++)
        {
            cin >> s[i] >> t[i];
            rank_[i] = i;
        }
        sort(rank_, rank_ + M, cmp);
        for (int i = 1, j = 0; i <= N && j < M; i++)
        {
            if (i == 7)
                int s = 0;
            if (list[i] <= N)
            {
                pos[list[i]].push_back(i);
                if (pos[list[i]].size() > list[i])
                    Update(1, 1, N, pos[list[i]][pos[list[i]].size() - list[i] - 1] + 1, pos[list[i]][pos[list[i]].size() - list[i]], 1);
                if (pos[list[i]].size() > list[i] + 1)
                    Update(1, 1, N, pos[list[i]][pos[list[i]].size() - list[i] - 2] + 1, pos[list[i]][pos[list[i]].size() - list[i] - 1], -1);
            }
            for (; t[rank_[j]] == i && j < M; j++)
                result[rank_[j]] = Query(1, 1, N, s[rank_[j]]);
        }
        for (int i = 0; i < M; i++)
            printf("%d
    ", result[i]);
        return 0;
    }
    
    void PushDown(int idx)
    {
        int left = idx << 1, right = (idx << 1) ^ 1;
        Tr[left] += mark[idx];
        mark[left] += mark[idx];
        Tr[right] += mark[idx];
        mark[right] += mark[idx];
        mark[idx] = 0;
    }
    
    void Update(int idx, int L, int R, int l, int r, int c)
    {
        if (l <= L && R <= r)
        {
            Tr[idx] += c;
            mark[idx] += c;
            return;
        }
        if (mark[idx])
            PushDown(idx);
        int mid = (L + R) >> 1, left = idx << 1, right = (idx << 1) ^ 1;
        if (l <= mid)
            Update(left, L, mid, l, r, c);
        if (mid < r)
            Update(right, mid + 1, R, l, r, c);
    }
    
    int Query(int idx, int L, int R, int x)
    {
        if (x == L & R == x)
            return Tr[idx];
        if (mark[idx])
            PushDown(idx);
        int mid = (L + R) >> 1, left = idx << 1, right = (idx << 1) ^ 1;
        if (x <= mid)
            return Query(left, L, mid, x);
        else
            return Query(right, mid + 1, R, x);
    }

    当然,作为线段树的好朋友,树状数组当然也可以做喽

    见:https://blog.csdn.net/u011026968/article/details/38589907

    感谢您的阅读,生活愉快~

  • 相关阅读:
    学习SpirngMVC之如何获取请求参数
    深入理解 CSS3 弹性盒布局模型
    JavaScript正则表达式验证大全(收集)
    我所认识的JavaScript正则表达式
    不再以讹传讹,GET和POST的真正区别
    JavaScript中的正则表达式
    Unicode 与 Unicode Transformation Format(UTF-8 / UTF-16 / UTF-32)
    PHP垃圾回收机制
    排序算法系列
    求最短路径算法系列
  • 原文地址:https://www.cnblogs.com/lv-anchoret/p/9063115.html
Copyright © 2011-2022 走看看