Loading

gym-103708C Candies median

Candies median

二分

直接二分答案,每次 \(check\) 的时候就遍历一次 \(k\) 算前缀和就好了

这题太具欺骗性了,之前一直以为是什么线段树,结果常数真的大

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 10;
ll a[maxn], b[maxn], c[maxn];
int n, q, k;

ll check(ll x)
{
    ll ans = 0;
    for(int i=0; i<k; i++)
    {
        ll r = min(b[i], x);
        ans += max(0ll, c[i] * (r - a[i] + 1));
    }
    return ans;
}

int main()
{
    scanf("%d%d", &n, &q);
    vector<int>num(n + 1);
    for(int i=1; i<=n; i++) scanf("%d", &num[i]);
    while(q--)
    {
        scanf("%d", &k);
        ll tot = 0;
        for(int i=0; i<k; i++)
        {
            scanf("%lld%lld%lld", &a[i], &b[i], &c[i]);
            tot += c[i] * (b[i] - a[i] + 1);
        }
        int l = 1, r = n;
        ll x = tot / 2 + 1;
        while(l < r)
        {
            int mid = l + r >> 1;
            if(check(mid) >= x) r = mid;
            else l = mid + 1;
        }
        double ans = 0;
        if(tot & 1) ans = num[r];
        else
        {
            if(r > 1 && check(r - 1) == x - 1)
                ans = (double)(num[r] + num[r-1]) / 2;
            else
                ans = num[r];
        }
        printf("%.10f\n", ans);
    }
    return 0;
}
posted @ 2022-08-30 14:42  dgsvygd  阅读(50)  评论(0编辑  收藏  举报