C. Number of Minimums on a Segment


link

同时维护线段树区间最小值和最小值的数量

code

#include <iostream>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <vector>
#include <set>

#include <algorithm>
#define forn(i, n) for (int i = 0; i < int(n); i++)
using namespace std;

inline int read(){
    int x = 0, op = 1; char ch = getchar();
    while (!isdigit(ch)){ if (ch == '-') op = -1; ch = getchar();}
    while (isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48), ch = getchar();}
    return x * op;
}

const int N = 1e5 + 100;
int a[N];

struct tree{
    int l, r;
    int mx;
    int cnt;
    int mid(){
        return (l + r) >> 1;
    }
}t[N << 2];

inline void push(int rt){
    t[rt].mx = min(t[rt << 1].mx, t[rt << 1|1].mx);
    if (t[rt << 1].mx ==  t[rt << 1|1].mx)
    {
        t[rt].cnt = t[rt << 1].cnt + t[rt << 1|1].cnt;
    }else if(t[rt << 1].mx < t[rt << 1|1].mx){
        t[rt].cnt = t[rt << 1].cnt;
    }else{
        t[rt].cnt = t[rt << 1|1].cnt;
    }
}

struct item
{
    int m, num;
};

inline void build(int rt, int l, int r){
    t[rt].l = l, t[rt].r = r;
    if (l == r)
    {
        t[rt].mx = a[l];
        t[rt].cnt = 1;
        return;
    }
    int mid = t[rt].mid();
    build(rt << 1, l, mid);
    build(rt << 1|1, mid + 1, r);
    push(rt);
}

inline void update(int rt, int pos, int val){
    if (t[rt].l == t[rt].r)
    {
        t[rt].mx = val;
        return;
    }

    int mid = t[rt].mid();
    if (pos <= mid)
    {
        update(rt << 1, pos, val);
    }else{
        update(rt << 1|1, pos, val);
    }
    push(rt);
}

item merge(item x, item y){
    if (x.m < y.m) return x;
    else if (x.m > y.m) return y;
    else return {x.m, x.num + y.num};
}

item query(int rt, int lb, int rb){
    item res = {INT_MAX, 0};
    if (t[rt].l >= lb && t[rt].r <= rb)
    {
        return item{t[rt].mx, t[rt].cnt};
    }
    int mid = t[rt].mid();
    if (mid >= lb)
    {
        res = merge(res, query(rt << 1, lb, rb));
    }
    if (mid < rb)
    {
        res = merge (res, query(rt << 1|1, lb, rb));
    }
    return res;
}


int n, m;
int main(int argc, char const *argv[])
{
    n = read(), m = read();
    for (int i = 1; i <= n; ++i)
    {
           a[i] = read();
    }
    build(1, 1, n);
    while(m--){
        int op = read(), x = read(), y = read();
        if (op == 1)
        {
            update(1, x + 1, y);
        }else{
            item ans = query(1, x + 1, y);
            printf("%d %d\n", ans.m, ans.num);
        }
    }
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
You are given an array a1,a2,…,an, where all elements are different. You have to perform exactly k operations with it. During each operation, you do exactly one of the following two actions (you choose which to do yourself): find two minimum elements in the array, and delete them; find the maximum element in the array, and delete it. You have to calculate the maximum possible sum of elements in the resulting array. Input The first line contains one integer t (1≤t≤104) — the number of test cases. Each test case consists of two lines: the first line contains two integers n and k (3≤n≤2⋅105; 1≤k≤99999; 2k<n) — the number of elements and operations, respectively. the second line contains n integers a1,a2,…,an (1≤ai≤109; all ai are different) — the elements of the array. Additional constraint on the input: the sum of n does not exceed 2⋅105. Output For each test case, print one integer — the maximum possible sum of elements in the resulting array. Example inputCopy 6 5 1 2 5 1 10 6 5 2 2 5 1 10 6 3 1 1 2 3 6 1 15 22 12 10 13 11 6 2 15 22 12 10 13 11 5 1 999999996 999999999 999999997 999999998 999999995 outputCopy 21 11 3 62 46 3999999986 Note In the first testcase, applying the first operation produces the following outcome: two minimums are 1 and 2; removing them leaves the array as [5,10,6], with sum 21; a maximum is 10; removing it leaves the array as [2,5,1,6], with sum 14. 21 is the best answer. In the second testcase, it's optimal to first erase two minimums, then a maximum.
05-13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值