題目希望你做到的事情:
給定一個陣列,找出 ind 最小且值大於等於 k 的資料,找到後回傳 ind
如果值不存在則回傳 0
這題的想法就是在線段樹上面進行二分搜
大概的想法就是每當抵達一個節點時就檢查他的左右子節點值的大小,如果大於等於的話就往下走,直到走到葉節點
當走到葉節點時,將值減去 k,並回傳 L 或 R(會剛好是 ind)
實作需要注意的事情:
seg[0]
的大小來取得(從定義可以知道 seg[0]
存的資料一定為整個樹最大的值)
/* Question : CSES 1143. Hotel Queries */
#include<bits/stdc++.h>
using namespace std;
#define opt ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define pirq(type) priority_queue<type, vector<type>, greater<type>>
#define mem(x, value) memset(x, value, sizeof(x));
#define pii pair<int, int>
#define pdd pair<double, double>
#define pb push_back
#define f first
#define s second
#define int long long
#define nL cnt * 2
#define nR cnt * 2 + 1
const auto dir = vector< pair<int, int> > { {1, 0}, {0, 1}, {-1, 0}, {0, -1} };
const int MAXN = 2e5 + 50;
const int Mod = 1e9 + 7;
int n, m, p, ans, hotel[MAXN], seg[MAXN*4];
int findk( int L, int R, int val, int cnt ){
if( L == R ){
seg[cnt] -= val;
return L;
}
int M = (L + R) / 2;
if( seg[nL] >= val ) ans = findk(L, M, val, nL);
else if( seg[nR] >= val ) ans = findk(M+1, R, val, nR);
seg[cnt] = max( seg[nL], seg[nR] );
return ans;
}
void build( int L, int R, int cnt ){
if( L == R ){
seg[cnt] = hotel[L];
return;
}
int M = (L + R) / 2;
build(L, M, nL);
build(M+1, R, nR);
seg[cnt] = max( seg[nL], seg[nR] );
}
signed main(){
opt;
cin >> n >> m;
for( int i = 1 ; i <= n ; i++ ) cin >> hotel[i];
build(1, n, 1);
for( int i = 0 ; i < m ; i++ ){
cin >> p;
ans = 0;
if( seg[1] < p ) cout << 0 << " \n"[i==m-1];
else cout << findk(1, n, p, 1) << " \n"[i==m-1];
}
}
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up