1. 程式人生 > >Luogu3527 POI2011 Meteors 整體二分、樹狀數組、差分

Luogu3527 POI2011 Meteors 整體二分、樹狀數組、差分

back getc owb main its 題目 sdi num ons

傳送門


比較板子的整體二分題目,時限有點緊註意常數

整體二分的過程中將時間在\([l,mid]\)之間的流星使用樹狀數組+差分進行維護,然後對所有國家查看一遍並分好類,遞歸下去,記得消除答案在\([mid+1,r]\)的詢問中時間在\([l,mid]\)的流星操作的貢獻

註意:可能存在某一段時間某一個國家的流星數量超過long long範圍,應該當某個時候國家流星量和大於等於國家需求值時直接退出,這樣可以避免這個問題。

#include<bits/stdc++.h>
#define INF 0x7fffffff
#define lowbit(x) ((x) & -(x)) 
using namespace std;

inline int read(){
    int a = 0;
    char c = getchar();
    while(!isdigit(c))
        c = getchar();
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return a;
}

const int MAXN = 3e5 + 10;
vector < int > bel[MAXN];
long long BIT[MAXN];
int qry[MAXN][2] , tp[2][MAXN][2] , mod[MAXN][3] , ans[MAXN];
int N , M , K;

inline void add(int p , int num){
    while(p <= M){
        BIT[p] += num;
        p += lowbit(p);
    }
}

inline long long get(int p){
    long long sum = 0;
    while(sum < 1e9 && p){
        sum += BIT[p];
        p -= lowbit(p);
    }
    return sum;
}

void solve(int ql , int qr , int l , int r){
    if(qr < ql)
        return;
    if(l == r){
        for(int i = ql ; i <= qr ; ++i)
            ans[qry[i][0]] = l;
        return;
    }
    int mid = (l + r) >> 1 , p0 = 0 , p1 = 0;
    for(int i = l ; i <= mid ; ++i){
        add(mod[i][1] + 1 , -mod[i][2]);
        add(mod[i][0] , mod[i][2]);
        if(mod[i][0] > mod[i][1])
            add(1 , mod[i][2]);
    }
    for(int i = ql ; i <= qr ; ++i){
        long long sum = 0;
        for(int j = 0 ; j < bel[qry[i][0]].size() && sum < qry[i][1] ; ++j)
            sum += get(bel[qry[i][0]][j]);
        if(sum >= qry[i][1]){
            tp[0][++p0][0] = qry[i][0];
            tp[0][p0][1] = qry[i][1]; 
        }
        else{
            tp[1][++p1][0] = qry[i][0];
            tp[1][p1][1] = qry[i][1] - sum;
        }
    } 
    memcpy(qry + ql , tp[0] + 1 , sizeof(int) * p0 * 2);
    memcpy(qry + ql + p0 , tp[1] + 1 , sizeof(int) * p1 * 2);
    for(int i = l ; i <= mid ; ++i){
        add(mod[i][1] + 1 , mod[i][2]);
        add(mod[i][0] , -mod[i][2]);
        if(mod[i][0] > mod[i][1])
            add(1 , -mod[i][2]);
    }
    solve(ql , ql + p0 - 1 , l , mid);
    solve(ql + p0 , qr , mid + 1 , r);
}

signed main(){
    N = read();
    M = read();
    for(int i = 1 ; i <= M ; ++i)
        bel[read()].push_back(i);
    for(int i = 1 ; i <= N ; ++i){
        qry[i][0] = i;
        qry[i][1] = read(); 
    }
    K = read();
    for(int i = 1 ; i <= K ; ++i){
        mod[i][0] = read();
        mod[i][1] = read();
        mod[i][2] = read();
    }
    solve(1 , N , 1 , K + 1);
    for(int i = 1 ; i <= N ; ++i)
        if(ans[i] == K + 1)
            puts("NIE");
        else
            printf("%d\n" , ans[i]);
    return 0;
}

Luogu3527 POI2011 Meteors 整體二分、樹狀數組、差分