[POI2011]MET-Meteors

题面

题解

首先我们尝试暴力,那么就对每个点二分一下即可。

我们发现单独二分复杂度太高,而且有些地方很浪费,如求前缀和等。

那么我们就想,能否将它们合并在一起二分呢?

于是就有了整体二分

整体二分即可。

代码

#include<cstdio>
#include<cstring>
#include<vector>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
#define clear(x, y) memset(x, y, sizeof(x));

inline int read()
{
    int data = 0, w = 1;
    char ch = getchar();
    while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if(ch == '-') w = -1, ch = getchar();
    while(ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    return data*w;
}

const int maxn(3e5 + 10);
struct node { int l, r; long long a; } r[maxn];
struct qry { int id; long long p; } p[maxn], pl[maxn], pr[maxn];
long long c[maxn]; std::vector<int> a[maxn];
int n, m, ans[maxn], K;
inline void add(int x, int v) { while(x <= m) c[x] += v, x += x & -x; }
inline long long query(int x) { long long ans = 0; while(x) ans += c[x], x -= x & -x; return ans; }
inline void fall(int x, int o)
{
    if(r[x].l > r[x].r) add(1, o * r[x].a);
    add(r[x].l, o * r[x].a); add(r[x].r + 1, -o * r[x].a);
}

inline bool check(int x, long long &sum)
{
    sum = 0;
    static std::vector<int>::iterator it;
    for(it = a[p[x].id].begin(); it != a[p[x].id].end(); ++it) { sum += query(*it); if(sum >= p[x].p) return true; }
    return false;
}

void Div(int l, int r, int ql, int qr)
{
    if(ql > qr) return;
    if(l == r) { for(RG int i = ql; i <= qr; i++) ans[p[i].id] = l; return; }

    int mid = (l + r) >> 1, tl = 0, tr = 0;
    long long sum;

    for(RG int i = l; i <= mid; i++) fall(i, 1);
    for(RG int i = ql; i <= qr; i++)
        if(check(i, sum)) pl[++tl] = p[i];
        else p[i].p -= sum, pr[++tr] = p[i];

    for(RG int i = l; i <= mid; i++) fall(i, -1);
    for(RG int i = 1; i <= tl; i++) p[i + ql - 1] = pl[i];
    for(RG int i = 1; i <= tr; i++) p[i + ql + tl - 1] = pr[i];
    Div(l, mid, ql, ql + tl - 1);
    Div(mid + 1, r, ql + tl, qr);
}

int main()
{
#ifndef ONLINE_JUDGE
    file(cpp);
#endif

    n = read(); m = read();
    for(RG int i = 1; i <= m; i++) a[read()].push_back(i);
    for(RG int i = 1; i <= n; i++) p[i] = (qry) {i, read()};
    K = read();
    for(RG int i = 1; i <= K; i++) r[i] = (node) {read(), read(), read()};
    r[++K] = (node) {1, m, 1000000000};

    Div(1, K, 1, n);
    for(RG int i = 1; i <= n; i++) ans[i] == K ? puts("NIE") : printf("%d\n", ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/cj-xxz/p/9800632.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值