日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【学习笔记】整体二分

發布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【学习笔记】整体二分 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 整體二分
  • 幾道模板題
    • Dynamic Rankings
    • [ZJOI2013]K大數查詢
    • [國家集訓隊]矩陣乘法
    • [THUPC2017] 天天愛射擊
    • [CTSC2018]混合果汁

例1. 給定 nnn 個數 aia_iai?一次詢問,詢問區間 [l,r][l,r][l,r] 中的第 kkk 小數。

我們通常想到二分答案,然后計數在 [l,r][l,r][l,r] 區間內 ≤x\le xx 的數的個數,再與 kkk 比較。

時間復雜度 O(nlog?n)O(n\log n)O(nlogn)。(盡管這并不是最優秀的做法)

例2. 給定 nnn 個數 aia_iai?多次詢問,詢問區間 [1,n][1,n][1,n] 中的第 kkk 小數。

由于區間是整個數列,所以我們直接排序一下,然后找第 kkk 個數即可,時間復雜度 O(nlog?n)O(n\log n)O(nlogn)

例3. 給定 nnn 個數 aia_iai?多次詢問,詢問區間 [l,r][l,r][l,r] 中的第 kkk 小數。

這是一道主席樹,即可持久化線段樹的模板題。建立權值線段樹然后 rrr 版本 ?l-l?l 版本,線段樹上二分。

實際上,我們仍然可以用二分做。

但如果對于每一個詢問都二分一次,那么時間復雜度 O(qnlog?n)O(qn\log n)O(qnlogn) 就爆炸了。

是否可以只用一次二分呢?——答案是顯然的。

我們理想的一次二分應該是二分一個答案 xxx,然后利用一個數據結構快速判斷答案和每一個詢問的大小關系,再將詢問分成 ≤x,>x\le x,>xx,>x 的兩部分,分別二分下去。

不難發現,這種假想的時間復雜度大概是帶兩個 logloglog 的。

例4. 給定 nnn 個數 aia_iai?多次詢問和修改某個位置的值,詢問區間 [l,r][l,r][l,r] 中的第 kkk 小數。

線段樹分治??不清楚。但這仍可以二分做。

整體二分

“引”中最后假想出來的思路就是 整體二分

能用整體二分解決的題目需要滿足以下性質:

  • 答案具有可二分性。
  • 修改對判斷答案的貢獻相互獨立,即修改之間互不影響。
  • 修改如果有貢獻,則是確定的貢獻,不會隨二分的答案產生變化。
  • 貢獻滿足交換律,結合律,具有廣義的可加性。
  • 離線。

總體算法思路:

  • [l,r][l,r][l,r] 為二分答案的值域,[ql,qr][ql,qr][ql,qr] 為定義域,即只考慮編號在 [ql,qr][ql,qr][ql,qr] 中的修改和詢問操作,這其中的詢問的答案在 [l,r][l,r][l,r] 內。
  • 首先把所有操作按 時間順序 存入數組。通常輸入順序即為操作的時間順序。然后開始分治。
  • 在每一層的分治中,利用數據結構(常見為樹狀數組/線段樹)統計當前查詢的答案和 mid\text{mid}mid 的關系。
  • 根據查詢的答案和 mid\text{mid}mid 之間的關系,分成 L,RL,RL,R 兩份,分別遞歸。
  • 類比線段樹分治,每一個分治的子問題都是互不相關的,但卻共用同一個數據結構。所以這里還要涉及到回退問題。
  • l=rl=rl=r 時,[ql,qr][ql,qr][ql,qr] 中的所有詢問答案即為 lll

下面以主席樹的模板題作為例題,具體闡釋算法實現以及時間復雜度的計算。

  • 將輸入 aia_iai? 的操作定義為類型 111,即 q[i].op=1q[i].op=1q[i].op=1。并記錄下 q[i]q[i]q[i] 修改的位置 iii,修改的值 aia_iai?

  • 將查詢 [l,r],k[l,r],k[l,r],k 的操作定義為類型 222。并記錄下詢問的區間,kkk

  • 對于一個形如 (l,r,ql,qr)(l,r,ql,qr)(l,r,ql,qr) 的子問題,二分答案為 mid=l+r>>1mid=l+r>>1mid=l+r>>1

  • 然后處理 [ql,qr][ql,qr][ql,qr] 范圍內的類型 111 操作。

    • 修改的值 ≤mid\le midmid 的。

      全都扔到數據結構上。(這里使用的是樹狀數組)

      則樹狀數組上放的是 ≤mid\le midmid 的且在 [ql,qr][ql,qr][ql,qr] 操作區間內的修改操作。

      再放入 LLL 數組中。

    • 修改的值 >mid>mid>mid 的。

      這種修改對于 midmidmid 答案沒有貢獻,直接放進 RRR 數組中。

  • 對于 [ql,qr][ql,qr][ql,qr] 范圍中的類型 222 操作。直接詢問樹狀數組中 [q[i].l,q[i].r][q[i].l,q[i].r][q[i].l,q[i].r] 區間內的個數 cntcntcnt

    • 如果 cnt≤q[i].kcnt\le q[i].kcntq[i].k

      也就是說 [q[i].l,q[i].r][q[i].l,q[i].r][q[i].l,q[i].r]≤mid\le midmid 的數 ≤k\le kk 個。答案要么是 midmidmid 要么 <mid<mid<mid

      根據二分原則,我們把這個詢問放到 LLL 數組中。

    • 如果 cnt>q[i].kcnt>q[i].kcnt>q[i].k

      類比線段樹二分,我們將 q[i].kq[i].kq[i].k 減去 cntcntcnt。然后放到 RRR 數組中。

      因為到時候處理 (mid+1,r,ql′,qr′)(mid+1,r,ql',qr')(mid+1,r,ql,qr) 的子問題時,原本 [q[i].l,q[i].r][q[i].l,q[i].r][q[i].l,q[i].r]≤mid\le midmid 的數時一定會提供 111 的個數,我們沒有必要每次都加入。

  • 將數據結構回退至當前層未操作前的模樣。

  • 此時的 LLL 數組放的詢問是真正 ans≤midans\le midansmid 的詢問,放的修改是重新計算時還可能被掛到樹狀數組上去的修改。

    RRR 數組同理。我們已經去掉了 LLL 數組中所有修改對 RRR 中詢問產生的貢獻。

    現在兩個數組之間的信息是完全不會有交的了。

    所以分治處理 (l,mid,L),(mid+1,r,R)(l,mid,L),(mid+1,r,R)(l,mid,L),(mid+1,r,R)

#include <bits/stdc++.h> using namespace std; #define maxn 400005 #define inf 0x7f7f7f7f int n, m; int ans[maxn]; struct node { int op, l, r, k, id; }q[maxn], Left[maxn], Right[maxn];namespace BIT {int t[maxn];void add( int i, int x ) { for( ;i <= n;i += i & -i ) t[i] += x; }int ask( int i ) { int cnt = 0; for( ;i;i -= i & -i ) cnt += t[i]; return cnt; } }void solve( int l, int r, int ql, int qr ) {if( ql > qr ) return;if( l == r ) { for( int i = ql;i <= qr;i ++ ) if( q[i].op == 2 ) ans[q[i].id] = l;return;}int mid = l + r >> 1, cntL = 0, cntR = 0;for( int i = ql;i <= qr;i ++ )if( q[i].op == 1 ) {if( q[i].k > mid ) Right[++ cntR] = q[i];else BIT :: add( q[i].id, 1 ), Left[++ cntL] = q[i];}else {int cnt = BIT :: ask( q[i].r ) - BIT :: ask( q[i].l - 1 );if( q[i].k <= cnt ) Left[++ cntL] = q[i];else q[i].k -= cnt, Right[++ cntR] = q[i];}for( int i = 1;i <= cntL;i ++ ) if( Left[i].op == 1 ) BIT :: add( Left[i].id, -1 );for( int i = 1;i <= cntL;i ++ ) q[i + ql - 1] = Left[i];for( int i = 1;i <= cntR;i ++ ) q[i + ql + cntL - 1] = Right[i];solve( l, mid, ql, ql + cntL - 1 );solve( mid + 1, r, ql + cntL, qr ); }int main() {scanf( "%d %d", &n, &m );for( int i = 1, x;i <= n;i ++ ) {scanf( "%d", &x );q[i] = (node){ 1, -inf, inf, x, i };}for( int i = 1, l, r, k;i <= m;i ++ ) {scanf( "%d %d %d", &l, &r, &k );q[i + n] = (node){ 2, l, r, k, i };}solve( -inf, inf, 1, n + m );for( int i = 1;i <= m;i ++ ) printf( "%d\n", ans[i] );return 0; }

最后來分析一下這個時間復雜度:

  • 首先是二分的答案值,O(log?V)O(\log V)O(logV) 的。
  • 對于同一層的分治,總共的區間定義域是 O(n)O(n)O(n)。類比線段樹 1,2,41,2,41,2,4 的劃分,但同一層的總和仍是 nnn
  • 每個數在同一層的若干個分治中最多只會被掛在數據結構上一次,然后撤銷。
  • 時間復雜度應為 O(nlog?nlog?V)O(n\log n\log V)O(nlognlogV)

幾道模板題

Dynamic Rankings

Dynamic Rankings

本題才是真的修改操作,即“引”中的例4 。

其實也沒有什么特別的,可以類比線段樹分治,一個數存在時間是一段連續的區間。

具體見代碼即可明白。

#include <bits/stdc++.h> using namespace std; #define maxn 400005 struct node { int op, x, y, k, id; }q[maxn], L[maxn], R[maxn]; int n, m; int ans[maxn], a[maxn];namespace BIT {int t[maxn];void add( int i, int x ) { for( ;i <= n;i += i & -i ) t[i] += x; }int ask( int i ) { int cnt = 0; for( ;i;i -= i & -i ) cnt += t[i]; return cnt; } }void solve( int l, int r, int ql, int qr ) {if( ql > qr ) return;if( l == r ) { for( int i = ql;i <= qr;i ++ ) if( q[i].op == 2 ) ans[q[i].id] = l; return; }int mid = l + r >> 1;int cntl = 0, cntr = 0;for( int i = ql;i <= qr;i ++ )if( q[i].op == 2 ) {int cnt = BIT :: ask( q[i].y ) - BIT :: ask( q[i].x - 1 );if( q[i].k <= cnt ) L[++ cntl] = q[i];else q[i].k -= cnt, R[++ cntr] = q[i];}else {if( q[i].x <= mid ) BIT :: add( q[i].k, q[i].y ), L[++ cntl] = q[i];else R[++ cntr] = q[i];}for( int i = ql;i <= qr;i ++ )if( q[i].op == 1 and q[i].x <= mid )BIT :: add( q[i].k, -q[i].y );for( int i = 1;i <= cntl;i ++ ) q[i + ql - 1] = L[i];for( int i = 1;i <= cntr;i ++ ) q[i + ql + cntl - 1] = R[i];solve( l, mid, ql, ql + cntl - 1 );solve( mid + 1, r, ql + cntl, qr ); }int main() {int cnt = 0, Max = 0;scanf( "%d %d", &n, &m );for( int i = 1;i <= n;i ++ ) {scanf( "%d", &a[i] );q[++ cnt] = (node){ 1, a[i], 1, i, cnt };Max = max( Max, a[i] );}char op[10]; int x, y, k;for( int i = 1;i <= m;i ++ ) {scanf( "%s", op );if( op[0] == 'Q' ) {scanf( "%d %d %d", &x, &y, &k );q[++ cnt] = (node) { 2, x, y, k, cnt };}else {scanf( "%d %d", &x, &y );q[++ cnt] = (node){ 1, a[x], -1, x, cnt };a[x] = y;q[++ cnt] = (node){ 1, a[x], 1, x, cnt };Max = max( Max, y );}}solve( 0, Max, 1, cnt );sort( q + 1, q + cnt + 1, []( node x, node y ) { return x.id < y.id; } );for( int i = 1;i <= cnt;i ++ )if( q[i].op == 2 ) printf( "%d\n", ans[q[i].id] );return 0; }

[ZJOI2013]K大數查詢

[ZJOI2013]K大數查詢

注意這里是 kkk 大數,不是 kkk 小數。

那么二分答案時候,把 >mid>mid>mid 的掛上去即可。

或者你整體取相反數后做 kkk 小數,最后輸出答案再取反回來也行。

#include <bits/stdc++.h> using namespace std; #define maxn 50005 #define int long long struct node { int op, x, y, k, id; }q[maxn], L[maxn], R[maxn]; int n, m; int ans[maxn];namespace SGT {struct node { int cnt, tag; }t[maxn << 2];#define lson now << 1#define rson now << 1 | 1#define mid (l + r >> 1)void pushdown( int now, int l, int r ) {if( ! t[now].tag ) return;t[lson].tag += t[now].tag;t[lson].cnt += t[now].tag * (mid - l + 1);t[rson].tag += t[now].tag;t[rson].cnt += t[now].tag * (r - mid);t[now].tag = 0;}void modify( int now, int l, int r, int L, int R, int x ) {if( R < l or r < L ) return;if( L <= l and r <= R ) { t[now].tag += x; t[now].cnt += x * (r - l + 1); return; }pushdown( now, l, r );modify( lson, l, mid, L, R, x );modify( rson, mid + 1, r, L, R, x );t[now].cnt = t[lson].cnt + t[rson].cnt;}int query( int now, int l, int r, int L, int R ) {if( R < l or r < L ) return 0;if( L <= l and r <= R ) return t[now].cnt;pushdown( now, l, r );return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R );}#undef lson#undef rson#undef mid }void solve( int l, int r, int ql, int qr ) {if( ql > qr ) return;if( l == r ) { for( int i = ql;i <= qr;i ++ ) ans[q[i].id] = l; return; }int mid = l + r >> 1;int cntl = 0, cntr = 0;for( int i = ql;i <= qr;i ++ )if( q[i].op == 1 ) {if( q[i].k > mid ) SGT :: modify( 1, 1, n, q[i].x, q[i].y, 1 ), R[++ cntr] = q[i];else L[++ cntl] = q[i];}else {int cnt = SGT :: query( 1, 1, n, q[i].x, q[i].y );if( q[i].k <= cnt ) R[++ cntr] = q[i];else q[i].k -= cnt, L[++ cntl] = q[i];}for( int i = 1;i <= cntr;i ++ )if( R[i].op == 1 )SGT :: modify( 1, 1, n, R[i].x, R[i].y, -1 );for( int i = 1;i <= cntl;i ++ ) q[ql + i - 1] = L[i];for( int i = 1;i <= cntr;i ++ ) q[ql + i + cntl - 1] = R[i];solve( mid + 1, r, ql + cntl, qr );solve( l, mid, ql, ql + cntl - 1 ); }signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1, op, x, y, k;i <= m;i ++ ) {scanf( "%lld %lld %lld %lld", &op, &x, &y, &k );q[i] = (node){ op, x, y, k, i };}solve( -n, n, 1, m );sort( q + 1, q + m + 1, []( node x, node y ) { return x.id < y.id; } );for( int i = 1;i <= m;i ++ ) if( q[i].op == 2 ) printf( "%lld\n", ans[q[i].id] );return 0; }

[國家集訓隊]矩陣乘法

[國家集訓隊]矩陣乘法

數據結構用二維樹狀數組即可。

#include <bits/stdc++.h> using namespace std; #define maxn 505 #define maxm 400005 struct node { int op, l1, r1, l2, r2, k, id; }q[maxm], L[maxm], R[maxm]; int n, m; int ans[maxm];namespace BIT {int t[maxn][maxn];void add( int x, int y, int v ) {for( int i = x;i <= n;i += i & -i )for( int j = y;j <= n;j += j & -j )t[i][j] += v;}int ask( int x, int y ) {int cnt = 0;for( int i = x;i;i -= i & -i )for( int j = y;j;j -= j & -j )cnt += t[i][j];return cnt;} }void solve( int l, int r, int ql, int qr ) {if( qr < ql ) return;if( l == r ) { for( int i = ql;i <= qr;i ++ ) ans[q[i].id] = l; return; }int mid = l + r >> 1;int cntl = 0, cntr = 0;for( int i = ql;i <= qr;i ++ )if( q[i].op == 1 ) {if( q[i].k <= mid ) BIT :: add( q[i].l1, q[i].r1, 1 ), L[++ cntl] = q[i];else R[++ cntr] = q[i];}else {int cnt = BIT :: ask( q[i].l2, q[i].r2 ) - BIT :: ask( q[i].l1 - 1, q[i].r2 ) - BIT :: ask( q[i].l2, q[i].r1 - 1 ) + BIT :: ask( q[i].l1 - 1, q[i].r1 - 1 );if( q[i].k <= cnt ) L[++ cntl] = q[i];else q[i].k -= cnt, R[++ cntr] = q[i];}for( int i = 1;i <= cntl;i ++ ) if( L[i].op == 1 ) BIT :: add( L[i].l1, L[i].r1, -1 );for( int i = 1;i <= cntl;i ++ ) q[ql + i - 1] = L[i];for( int i = 1;i <= cntr;i ++ ) q[ql + cntl + i - 1] = R[i];solve( l, mid, ql, ql + cntl - 1 );solve( mid + 1, r, ql + cntl, qr ); }int main() {scanf( "%d %d", &n, &m );int cnt = 0;for( int i = 1;i <= n;i ++ )for( int j = 1, x;j <= n;j ++ ) {scanf( "%d", &x );q[++ cnt] = (node){ 1, i, j, i, j, x, cnt };}for( int i = 1, l1, r1, l2, r2, k;i <= m;i ++ ) {scanf( "%d %d %d %d %d", &l1, &r1, &l2, &r2, &k );q[++ cnt] = (node){ 2, l1, r1, l2, r2, k, cnt };}solve( 0, 1e9, 1, cnt );sort( q + 1, q + cnt + 1, []( node x, node y ) { return x.id < y.id; } );for( int i = 1;i <= cnt;i ++ ) if( q[i].op == 2 ) printf( "%d\n", ans[q[i].id] );return 0; }

[THUPC2017] 天天愛射擊

[THUPC2017] 天天愛射擊

直接從子彈入手并不好做,這里稍微繞個彎,當我們知道所有木板最后一次被哪顆子彈射中,就能統計出每個子彈射穿的木板數。

所以應當以木板為因變量。考慮每次二分最后被射擊的子彈 midmidmid,然后 check\text{check}checkmidmidmid 個子彈能否射穿該木板。

發現這個可以整體二分做。

這里的 [l,r][l,r][l,r] 不再是權值,而是二分的子彈編號。

我們這里依然把子彈和木板放在同一個操作數組里面,子彈為類型 111,木板為類型 222

注意兩種操作的時間順序安排,我們應該是先把所有子彈打了過后,再檢查該木板被射中的次數是否達到承載值。

單點修改,區間查詢,樹狀數組可做。

如果次數到達承載值,證明可能在更早時刻就已經被射穿,放入左邊,否則放入右邊,遞歸分治。

#include <bits/stdc++.h> using namespace std; #define maxn 400005 struct node { int op, x, y, k, id; }q[maxn], L[maxn], R[maxn]; int n, m; int ans[maxn];namespace BIT {int t[maxn];void add( int i, int x ) { for( ;i < maxn;i += i & -i ) t[i] += x; }int ask( int i ) { int cnt = 0; for( ;i;i -= i & -i ) cnt += t[i]; return cnt; } }void solve( int l, int r, int ql, int qr ) {if( ql > qr ) return;if( l == r ) { for( int i = ql;i <= qr;i ++ ) if( q[i].op == 2 ) ans[l] ++; return; }int mid = l + r >> 1;int cntl = 0, cntr = 0;for( int i = ql;i <= qr;i ++ )if( q[i].op == 1 ) {if( q[i].k <= mid ) BIT :: add( q[i].x, 1 ), L[++ cntl] = q[i];else R[++ cntr] = q[i];}else {int cnt = BIT :: ask( q[i].y ) - BIT :: ask( q[i].x - 1 );if( q[i].k <= cnt ) L[++ cntl] = q[i];else q[i].k -= cnt, R[++ cntr] = q[i];}for( int i = 1;i <= cntl;i ++ ) if( L[i].op == 1 ) BIT :: add( L[i].x, -1 );for( int i = 1;i <= cntl;i ++ ) q[ql + i - 1] = L[i];for( int i = 1;i <= cntr;i ++ ) q[ql + cntl + i - 1] = R[i];solve( l, mid, ql, ql + cntl - 1 );solve( mid + 1, r, ql + cntl, qr ); }int main() {scanf( "%d %d", &n, &m );for( int i = 1, x, y, k;i <= n;i ++ ) {scanf( "%d %d %d", &x, &y, &k );q[i + m] = (node){ 2, x, y, k, i + m };}for( int i = 1, x;i <= m;i ++ ) {scanf( "%d", &x );q[i] = (node){ 1, x, 0, i, i };}solve( 1, m + 1, 1, n + m );for( int i = 1;i <= m;i ++ ) printf( "%d\n", ans[i] );return 0; }

[CTSC2018]混合果汁

[CTSC2018]混合果汁

顯然我們可以整體二分最低的美味度 midmidmid

然后把所有美味度 ≥mid\ge midmid 的果汁都放入數據結構中。

但果汁有錢數和購買上限。

在二分后有個顯然的貪心:越便宜的越先買。

我們可以用權值線段樹,以單價為下標,然后記錄總個數和總支付錢數。

查詢時先看左區間,再看右區間。查詢買最便宜的 lll 個的錢數是否在小朋友承受范圍內。

但這里我們發現,好像這里的貢獻提前去掉和前面幾個模板題目不太一樣。因為當 midmidmid 移動時可能會加入更便宜的果汁,所以我們不能在現在就把某些小朋友的錢數減去一部分。

那怎么辦?——我們直接不減,就只是把小朋友不斷分組即可。

每次撤銷就類似莫隊,用一個指針移動。仔細想想(可見下面代碼)每一種果汁最多上線段樹兩次。

總時間復雜度是可以保證的。

本題我將果汁和小朋友兩種操作分開存的,可能更直白一點。

這里的順序不再是時間順序,而是果汁美味度大小的順序。

#include <bits/stdc++.h> using namespace std; #define int long long #define maxn 100005 struct juice { int d, p, l; }g[maxn]; struct child { int g, l, id; }q[maxn], L[maxn], R[maxn]; int n, m, now; int ans[maxn];namespace SGT {struct node { int cnt, sum; }t[maxn << 2];#define lson now << 1#define rson now << 1 | 1#define mid (l + r >> 1)void modify( int p, int x, int now = 1, int l = 1, int r = 1e5 ) {if( l == r ) { t[now].cnt += x; t[now].sum += x * p; return; }if( p <= mid ) modify( p, x, lson, l, mid );else modify( p, x, rson, mid + 1, r );t[now].cnt = t[lson].cnt + t[rson].cnt;t[now].sum = t[lson].sum + t[rson].sum;}int query( int x, int now = 1, int l = 1, int r = 1e5 ) {if( ! x ) return 0;if( l == r ) return l * x;if( x <= t[lson].cnt ) return query( x, lson, l, mid );else return t[lson].sum + query( x - t[lson].cnt, rson, mid + 1, r );}#undef lson#undef rson#undef mid }void solve( int l, int r, int ql, int qr ) {if( ql > qr ) return;if( l == r ) { for( int i = ql;i <= qr;i ++ ) ans[q[i].id] = g[l].d; return; }int mid = l + r >> 1;while( now < mid ) ++ now, SGT :: modify( g[now].p, g[now].l );while( mid < now ) SGT :: modify( g[now].p, -g[now].l ), now --;int cntl = 0, cntr = 0;for( int i = ql;i <= qr;i ++ ) {if( SGT :: t[1].cnt < q[i].l ) R[++ cntr] = q[i];else if( SGT :: query( q[i].l ) <= q[i].g ) L[++ cntl] = q[i];else R[++ cntr] = q[i];}for( int i = 1;i <= cntl;i ++ ) q[ql + i - 1] = L[i];for( int i = 1;i <= cntr;i ++ ) q[ql + cntl + i - 1] = R[i];solve( l, mid, ql, ql + cntl - 1 );solve( mid + 1, r, ql + cntl, qr ); }signed main() {scanf( "%lld %lld", &n, &m );for( int i = 1;i <= n;i ++ ) scanf( "%lld %lld %lld", &g[i].d, &g[i].p, &g[i].l );for( int i = 1;i <= m;i ++ ) scanf( "%lld %lld", &q[i].g, &q[i].l ), q[i].id = i;sort( g + 1, g + n + 1, []( juice x, juice y ) { return x.d > y.d; } );g[++ n] = { -1, 0, (int)1e18 };solve( 1, n, 1, m );for( int i = 1;i <= m;i ++ ) printf( "%lld\n", ans[i] );return 0; }

總結

以上是生活随笔為你收集整理的【学习笔记】整体二分的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 在线观看亚洲一区二区 | 91干干| 欧美人与禽zozzo性之恋的特点 | 日皮视频免费看 | 精品国产一区二区三区四区阿崩 | 蜜臀aⅴ国产精品久久久国产老师 | 久久免费视频播放 | 欧美国产在线视频 | 国产精品国语对白 | 黄色大片在线 | 色老头一区二区 | 揄拍自拍 | 激情第四色 | 欧美日本在线播放 | 成人va在线观看 | 成人黄色一级片 | 亚洲精品在 | 欧美人体视频 | 九九九九久久久久 | 日韩一区二区三区精品 | 4438全国最大成人网 | 日日夜夜操操操 | 日本综合视频 | julia一区二区三区中文字幕 | 欧美视频www | 亚洲国产日韩在线 | 久久久久久亚洲中文字幕无码 | 波多野结衣欲乱上班族 | 国产97视频 | 五月天综合网站 | 久久色在线观看 | 国产乱淫精品一区二区三区毛片 | 日韩精品一区二区三区电影 | 永久免费未网 | 亚洲一区欧美一区 | 日韩av中文在线 | 青青草社区视频 | 色激情五月 | av最新版天堂资源在线 | 超碰成人在线免费观看 | 国产a国产片 | 免费在线观看你懂的 | 欧洲精品一区二区三区 | 精品中文字幕一区 | 国产东北真实交换多p免视频 | 色婷婷av一区二区三区之红樱桃 | 亚洲一区视频网站 | 五月天婷婷激情网 | 精品国产一区二区视频 | 在线h片| 久久精品色欲国产AV一区二区 | 亚洲欧美一区二区三区四区五区 | 体内射精一区二区 | 青青视频二区 | 清纯粉嫩极品夜夜嗨av | 播色屋| 蜜臀av性久久久久蜜臀aⅴ | 成年人晚上看的视频 | 国产不卡一区二区视频 | 黄色三级视频在线观看 | 91亚洲精品一区 | 国产激情成人 | 久久久久久久久久久网 | 成人免费精品视频 | 欧美三级视频在线观看 | 欧美成人午夜视频 | 手机免费看av | 91婷婷在线 | 精品免费在线 | 亚欧洲精品视频 | 99网站| 午夜电影在线播放 | 日本三级小视频 | 国产精品久久欧美久久一区 | a级无遮挡超级高清-在线观看 | 国产又粗又长又黄的视频 | 国产乱人伦app精品久久 | 色午夜av | 热播之家 | 日韩美一区二区 | 91精产国品一二三区在线观看 | av免费久久 | 在线中文字幕一区 | 黄色一级片免费在线观看 | 91精品国产自产91精品 | 性做久久久久久久久久 | 免费av网站在线 | 影音先锋成人资源站 | 天天摸天天做天天爽水多 | 国产高清视频免费 | 精品影视一区二区 | 九九免费精品视频 | 都市激情 亚洲 | 香蕉久久精品日日躁夜夜躁 | 少妇精品高潮欲妇又嫩中文字幕 | 国产性av | 天天射天天射天天射 | 中文字幕在线导航 | 天天干夜夜添 |