小Z的糖果难题【树状数组+离线查询】

题目链接

西南科技大学第十三届程序设计竞赛G题


Description 

小ZZ十分喜欢吃糖果, 于是他购买了nn颗糖果(从左到右放成一排,编号 1−n1−n ),每颗糖果都有一个甜度值wiwi 。

小ZZ由于吃了太多的糖果,以至于只有当他吃了比之前吃的糖果都甜的糖果时(wnow>wprewnow>wpre),他才感觉到 "吃" 了一颗糖果。

为了更有效的 "吃" 糖果,他想知道当他从第 ll 颗糖吃到第 rr 颗糖果,他 "吃" 了多少颗糖果(可以认为在吃第 ll 颗糖果之前他吃了一颗甜度值为 00 的糖果,不计入答案)。

Input 

第一行包含一个整数 T (1≤T≤1000)T (1≤T≤1000) 代表测试组数,对于每一组测试:

第一行两个整数 nn,qq (1≤n≤105,1≤q≤105)(1≤n≤105,1≤q≤105)  分别表示糖果的颗数,询问的次数(每次询问独立,即每次询问的操作都是在最初的糖果上进行的)。

第二行 nn 个整数 wi (1≤wi≤n)wi (1≤wi≤n),表示糖果的甜度值。

接下来 qq 行,每一行两个整数 li,ri (1≤li≤ri≤n)li,ri (1≤li≤ri≤n) 表示从第 lili 颗糖吃到第 riri 颗糖果。

数据保证所有测试的 n,qn,q 的和不会超过 106106。

Output 

对于每组测试,输出 qq 行,每行包含一个整数,表示小ZZ从第 lili 颗糖吃到第 riri 颗糖果, "吃" 的糖果 的数量。

1 6 3 2 1 3 5 4 5 1 6 2 5 5 6

3 3 2

Hint 

小ZZ从第 11 颗吃到第 66 颗时:"吃" 了第 1,3,41,3,4 颗糖果。

小ZZ从第 22 颗吃到第 55 颗时:"吃" 了第 2,3,42,3,4 颗糖果。

小ZZ从第 55 颗吃到第 66 颗时:"吃" 了第 5,6,5,6, 颗糖果。


  有点类似于REQ这道题的思路。

  的确是一道很不错的题,有大佬用LCA的倍增去写,2000+ms,不如写树状数组来的快,1000-ms即可。

  但是树状数组的确需要些思维,想了好久才想明白,也怪不得比赛的时候没能做出来,我们从右区间降序的角度去看,从右往左去维护关系。

  先使用单调栈用来维护一下,第一个大于等于该点的点的所在的位置,然后这样子就建立了关系,同样的,这个点被指向了,就代表着后面有比它小的节点,所以,当我们的区间包含它的时候,需要这样的减去对应的值,同样的,当右区间缩过来的时候,需要将指向的点把值给加回去“+1”,这样就是把关系还回去并且推出的意思了。

  可以去写写REQ这个问题,会理解的更加清晰(那道题更难些,但是个经典问题)。

 

最后,举个例子方便大家理解:

我给出的数为(9个):5、7、6、2、6、6、2、7、8

先看看挪动左端点,

对应的,我们从第9个开始,树状数组+1开始;

到第8个,发现后面没有比它"≥"的,那么继续+1;

同理,第7个;

但是对于第6个,是2(第7个)的对应的第一个"≤"那么,就+1-1变成了"+0",不做变化了;

对于第5个,被(6)第6个的对应的"≤"那么,也同样的是+1-1;

对于第4个,没有被后面的所指向(不是左边的第一个"≥"即可),直接+1就是了;

第3个的时候,会被后面的2(第4个)、6(第5个)所指向,所以变成了+1-2,是-1的更新;

第2个,-1,……类推;

然后,我们就要挪动右端点了,

挪动第9个的时候,前面没有比它大的,不考虑了;

挪动第8个的时候,给予第2个(7值)上的进行+1,也就是还回去的意思了;

挪动第7个的时候,给予第6个+1;

……

以此类推,还给所指向的"≥"它的节点一个数即可。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define esp 1e-6
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, Q, a[maxN], trie[maxN], ans[maxN];
struct Question
{
    int l, r, id;
    Question(int a=0, int b=0, int c=0):l(a), r(b), id(c) {}
}op[maxN];
bool cmp(Question e1, Question e2) { return e1.r > e2.r; }
inline void update(int i, int x)
{
    if(i == 0) return;
    while(i <= N)
    {
        trie[i] += x;
        i += lowbit(i);
    }
}
inline int query(int i)
{
    int ans = 0;
    while(i)
    {
        ans += trie[i];
        i -= lowbit(i);
    }
    return ans;
}
struct node
{
    int id, val;
    node(int a=0, int b=0):id(a), val(b) {}
};
stack<node> st;
int to[maxN];   //上一个比它大的节点的所在位置,为0就是没了
int behind[maxN];   //在下一个比它大的数之前,有几个数比它小或者等于
inline void init()
{
    for(int i=1; i<=N; i++) trie[i] = behind[i] = 0;
    while(!st.empty()) st.pop();
}
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        scanf("%d%d", &N, &Q);
        for(int i=1; i<=N; i++) scanf("%d", &a[i]);
        for(int i=1; i<=Q; i++) { scanf("%d%d", &op[i].l, &op[i].r); op[i].id = i; }
        sort(op + 1, op + Q + 1, cmp);
        init();
        to[1] = 0;
        st.push(node(1, a[1]));
        for(int i=2; i<=N; i++)
        {
            node tmp;
            to[i] = 0;
            while(!st.empty())
            {
                tmp = st.top();
                if(tmp.val >= a[i])
                {
                    to[i] = tmp.id;
                    //behind[tmp.id] = i - tmp.id;
                    behind[tmp.id]++;
                    break;
                }
                else st.pop();
            }
            st.push(node(i, a[i]));
        }
        int l = N, r = N;
        for(int q=1; q<=Q; q++)
        {
            while(r > op[q].r)
            {
                update(to[r], 1);
                r--;
            }
            while(l >= op[q].l)
            {
                update(l, -behind[l] + 1);
                l--;
            }
            ans[op[q].id] = query(op[q].r) - query(op[q].l - 1);
        }
        for(int i=1; i<=Q; i++) printf("%d\n", ans[i]);
    }
    return 0;
}
/*
1
9 7
5 7 6 2 6 6 2 7 8
6 9
5 7
9 9
1 4
5 9
4 7
2 9
*/

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
糖果MES系统小程序是一款专为糖果生产企业所设计开发的生产管理系统小程序。它通过与企业现有的MES系统进行数据对接,帮助企业实现更高效的糖果生产管理和生产过程监控。 首先,苦糖果MES系统小程序提供了设备监控功能。通过与企业现有的设备连接,实时监测设备的运行状态和生产数据,包括设备的开机时间、停机时间、生产数量等等。这样,企业可以随时查看设备运行状态,及时发现异常情况并进行处理,提高设备的利用率和生产效率。 其次,苦糖果MES系统小程序还提供了生产计划管理功能。企业可以在系统中创建生产计划并安排生产任务,系统会根据设备的状态和产能自动进行任务分配。同时,系统还能按照生产计划的优先级进行任务排序,确保重要订单的优先生产。这样,企业可以更加科学和有序地安排生产计划,提高生产效率。 此外,苦糖果MES系统小程序还提供了生产数据分析功能。系统会自动收集设备和生产过程中的各种数据,并生成相应的报表。企业可以通过这些报表,全面了解生产过程中的各项指标,如生产速度、故障率、产量等等。这样,企业可以及时发现生产中存在的问题,并采取相应的措施进行优化和改进。 总之,苦糖果MES系统小程序通过设备监控、生产计划管理和数据分析等功能,帮助糖果生产企业实现生产过程的精细化管理和优化,提高生产效率和质量,进一步提升企业竞争力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值