【CDQ或并行二分】 SPOJ METEORS

通道

题意:有m个空间站组成一个环形的轨道,每个空间站属于n个国家之一。一次流星雨可以给一段连续的空间站带来同样数量的陨石样本。给出每个国家需要的陨石数量和流星雨的出现情况,问每个国家最快在多少次流星雨前就能收集到需要数量的陨石

思路:分别二分算出答案即可

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

const int MAX_N = 300007;

typedef pair<int,int> pii;
typedef long long ll;

template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c = getchar() , c == EOF) return false;
    while(c != '-' && (c < '0' || c > '9')) c = getchar();
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return true;
}

struct Meteor {
    int l, r;
    ll v;
} meteor[MAX_N];
int n, m, k;
ll p[MAX_N];
int L[MAX_N], R[MAX_N], M[MAX_N];
pii unsolve[MAX_N];
bool suit[MAX_N];
vector<int> v[MAX_N];

struct Bit {
    ll bit[MAX_N];
    void clear() {
        memset(bit, 0, sizeof bit);
    }
    void add(int i, ll v) {
        for (;i < MAX_N; i += i & -i)
            bit[i] += v;
    }
    ll query(int i) {
        ll re = 0;
        for (;i > 0; i -= i & -i)
            re += bit[i];
        return re;
    }
} B;

void update(int id) {
    if (meteor[id].l <= meteor[id].r) {
        B.add(meteor[id].l, meteor[id].v);
        B.add(meteor[id].r + 1, -meteor[id].v);
    } else {
        B.add(meteor[id].l, meteor[id].v);
        B.add(m + 1, -meteor[id].v);
        B.add(1, meteor[id].v);
        B.add(meteor[id].r + 1, -meteor[id].v);
    }
}

void mid() {
    B.clear();
    int now = 0;
    for (int i = 1; i <= n; ++i) if (L[i] != R[i]) 
        unsolve[now++] = make_pair(M[i], i);
    int j = 1;
    sort(unsolve, unsolve + now);
    for (int i = 0; i < now; ++i) {
        while (j <= k && j <= unsolve[i].first) update(j++);
        int id = unsolve[i].second;
        ll now = 0;suit[id] = 0;
        for (int jj = 0; jj < v[id].size(); ++jj) {
            now += B.query(v[id][jj]);
            if (now >= p[id]) suit[id] = 1;
        }
    }
}

int main() {
    rd(n), rd(m);
    for (int i = 1; i <= m; ++i) {
        int x; rd(x);
        v[x].push_back(i);
    }
    for (int i = 1; i <= n; ++i) 
        rd(p[i]);
    rd(k);
    for (int i = 1; i <= k; ++i) 
        rd(meteor[i].l), rd(meteor[i].r), rd(meteor[i].v);
    for (int i = 1; i <= n; ++i) L[i] = 1, R[i] = k + 1;
    while (true) {
        for (int i = 1; i <= n; ++i)
            M[i] = L[i] + R[i] >> 1;
        mid();
        bool ok = false;
        for (int i = 1; i <= n; ++i) if (L[i] != R[i]) {
            if (suit[i]) R[i] = M[i];
            else L[i] = M[i] + 1;
            ok = true;
        }
        if (!ok) break;
    }
    for (int i = 1; i <= n; ++i) if (L[i] <= k) printf("%d\n", L[i]);
    else puts("NIE");
    return 0;
}
View Code

 

posted @ 2015-10-11 18:44  mithrilhan  阅读(220)  评论(0编辑  收藏  举报