暑假前专题题解---数据结构---F

本文介绍了一种利用离散化和线段树解决特定区间查询问题的方法。通过预处理大量数据并构建线段树,实现快速区间求和、最大值及最小值查询,适用于A值较大情况下的优化解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

题目转送门:http://qscoj.cn/#/problem/show/1921

 

因为A很大,所以需要先离散化,然后建树,对于每个A - len 的位置二分查找位置,用线段树询问区间和最大最小值即可

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
struct node { int A,B; }p[maxn];
int sum[maxn<<2],maxx[maxn<<2],minn[maxn<<2];
int sum1,max1 = -INT_MAX,min1 = INT_MAX;
int n,c,len;
void up(int id){
    sum[id] = sum[id<<1] + sum[id<<1|1];
    maxx[id] = max(maxx[id<<1] , maxx[id<<1|1]);
    minn[id] = min(minn[id<<1] , minn[id<<1|1]);
}
void build(int l,int r,int id){
    if (l == r){
        sum[id] = p[l].B;
        maxx[id] = p[l].B;
        minn[id] = p[l].B;
        return ;
    }
    int mid = (l + r) >> 1;
    build(l, mid, id<<1);
    build(mid+1, r, id<<1|1);
    up(id);
}
void query(int l,int r,int L,int R,int id){
    if (L <= l && r <= R){
        sum1 += sum[id];
        max1 = max(max1, maxx[id]);
        min1 = min(min1, minn[id]);
        return;
    }
    int mid = (l + r )>> 1;
    if (L <= mid) query(l, mid, L, R, id<<1);
    if (R > mid) query(mid+1, r, L, R, id<<1|1);
}
int low(int v){
    int l = 1, r = n;
    while (l != r) {
        int mid = (l + r) >> 1;
        if (p[mid].A > v) r = mid;
        else l = mid + 1;
    }
    return l;
}
int solve(string k,string fun){
    int cnt = 0;
    for (int i=2; i<=n; i++) {
        int x = low(p[i].A - len);
        while (p[x].A > p[i].A - len && x != 1) x--;
        while (p[x].A < p[i].A - len) x++;
        query(1, n, x, i-1, 1);
        if (k == "gt"){
            if (fun == "min"){
                if (p[i].B > min1) cnt++;
            }else if (fun == "max"){
                if (p[i].B > max1) cnt++;
            }else if (fun == "avg"){
                if (p[i].B*(i-x) > sum1) cnt++;
            }
        }else if (k == "lt"){
            if (fun == "min"){
                if (p[i].B < min1) cnt++;
            }else if (fun == "max"){
                if (p[i].B < max1) cnt++;
            }else if (fun == "avg"){
                if (p[i].B*(i-x) < sum1) cnt++;
            }
        }
        sum1 = 0; max1 = -INT_MAX; min1 = INT_MAX;
    }
    return cnt;
}
int main(){
    cin >> n >> c;
    for (int i=1; i<=n; i++)
        cin >> p[i].A >> p[i].B;
    build(1, n, 1);
    string k,fun;
    for (int i=0; i<c; i++) {
        cin >> k >> fun >> len;
        cout << solve(k, fun) << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值