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;
}