# Binary Search# Block Decomposition# Prefix Sum# Update

f033 - 攗皥蒽快給我去工作!!!- 續

🔗 前往 ZeroJudge 原題

題目描述

題目描述了攗皥蒽不斷被欺負和搶錢的故事,並給出一個工作賺錢的場景。總共有 n 天的工作,每天的工資 a_i。需要處理 q 個查詢,查詢分為兩種:

  1. 更新:將第 p 天的工資修改為 c。
  2. 查詢:找到最小的 x,使得從第 1 天到第 x 天的工資總和大於等於 k。如果無法達到,輸出 "meh"。

解題思路

這題可以使用分塊 (Block Decomposition) 來優化查詢和更新操作。

  1. 分塊: 將 n 個工作分成若干塊,每塊包含 len = sqrt(n) 個工作。
  2. 預處理: 計算每個塊的總和 (global),並儲存每個塊中的所有工資 (local)。
  3. 更新: 當需要更新工資時,找到對應的塊,更新該塊的總和和該塊中的工資。
  4. 查詢: 當需要查詢時,從第一塊開始累加塊的總和,直到總和大於等於 k。然後,在最後一個塊中,逐個累加工資,直到總和大於等於 k。

使用分塊可以將更新和查詢的平均時間複雜度降低到 sqrt(n)。

複雜度分析

  • 時間複雜度: O(n + q * sqrt(n))
    • 預處理 (build): O(n)
    • 更新 (update): O(sqrt(n))
    • 查詢 (query): O(sqrt(n))
    • 總體: O(n + q * sqrt(n))
  • 空間複雜度: O(n)
    • 儲存每個塊的工資和總和需要 O(n) 空間。

程式碼

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
//分塊結構
//假設要求區間總和
struct blk{
    vector<long long> local;    //每塊的全部元素
    long long global;           //儲存每塊的總和
    blk(){                //初始化
        local.clear();    //清空區間元素
        global = 0; //將區間總和先設為0
    }
};
long long n,m,x,z,len,num;
vector<blk> b(500005);
void build(){
	len=sqrt(n);
	//cout << "len = " << len << "\n";
	num=(n+len-1)/len;
    long long input;
    for(int i=0;i<n;i++){    //第i個元素分在第 i/len 塊
        cin>>input;
        //存入區間中
        b[i/len].local.push_back(input);
        //更新區間總和
        b[i/len].global += input;
    }
}
void update(long long q,long long v){
	long long blk=q/len,i=q%len;
	b[blk].global+=v-b[blk].local[i];
	b[blk].local[i]=v;
	return;
}
long long query(long long q){
	long long rt=0,sum=0;
	for(int i=0;i<num;++i){
		sum+=b[i].global;
		rt+=len;
		if(sum>=q){
			sum-=b[i].global;
			rt-=len;
			for(int j=0;j<len;++j){
				sum+=b[i].local[j];
				rt++;
				if(sum>=q)return rt;
			}
		}
	}
	return -1;
}
char is;
int main(){
	std::ios::sync_with_stdio(false);
    cin.tie(NULL);
	cin >> n >> m;
	build();
	for(int i=0;i<m;++i){
		cin >> is;
		if(is=='2'){
			cin >> x ;
			long long ans=query(x);
			if(ans==-1){
				cout << "meh\n";
			}
			else{
				cout << ans << '\n';
			}
		}
		else{
			cin >> x >> z;
			update(x-1,z);
		}
	}
}

Discussion