HDU 4417 Super Mario (樹狀陣列+離線處理)(劃分樹+二分答案)
題意: 給定1--n區間,有q個詢問,詢問l,r,k表示區間[l,r]小於等於k的數的個數
思路: 可以用劃分樹(求區間第k大值)變形一下,來求小於等於k的個數,但是此題直接離線處理詢問高效的多。
首先將1--n區間的值記錄位置,從小到大排序,每個詢問按照k值從小到大排序,然後從小到大開始,根據查詢的H,將滿足條件的的點插入,計數+1,然後就是求區間和。
#include <iostream> #include <algorithm> #include <cmath> #include<functional> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <vector> #include <set> #include <queue> #include <stack> #include <climits>//形如INT_MAX一類的 #define MAX 100001 using namespace std; inline void RD(int &ret) { char c; do { c = getchar(); } while(c < '0' || c > '9') ; ret = c - '0'; while((c=getchar()) >= '0' && c <= '9') ret = ret * 10 + ( c - '0' ); } void OT(int a) { if(a >= 10)OT(a / 10); putchar(a % 10 + '0'); } int n,q; struct node { int v,id; } a[MAX]; int c[MAX]; struct QES { int l,r,h,id; } qes[MAX]; int ans[MAX]; bool cmp(const node &a, const node &b) { return a.v < b.v; } bool cmp2(const QES &a, const QES &b) { return a.h < b.h; } int lowbit(int x) { return x & (-x); } void update(int x,int va) { while(x <= n) { c[x] += va; x += lowbit(x); } } int query(int x) { int ans = 0; while(x > 0) { ans += c[x]; x -= lowbit(x); } return ans; } int main() { int T; cin >> T; int ca = 1; while(T--) { RD(n); RD(q); memset(c,0,sizeof(c)); for(int i=1; i<=n; i++) { RD(a[i].v); a[i].id = i; } sort(a+1,a+1+n,cmp); for(int i=0; i<q; i++) RD(qes[i].l),RD(qes[i].r),RD(qes[i].h),qes[i].id = i; sort(qes,qes+q,cmp2); int order = 1; for(int i=0; i<q; i++) { while(a[order].v <= qes[i].h && order <= n) { update(a[order].id,1); order ++; } ans[qes[i].id] = query(qes[i].r+1) - query(qes[i].l); } printf("Case %d:\n",ca++); for(int i=0; i<q; i++)OT(ans[i]),puts(""); } return 0; }
劃分樹:
要求的是小於等於k的個數,可以二分該個數mid,找到的也是第mid小的值,與k大小比較,直到得到答案
#include <iostream> #include <algorithm> #include <cmath> #include<functional> #include <cstdio> #include <cstdlib> #include <cstring> #include <string> #include <vector> #include <set> #include <queue> #include <stack> #include <climits>//形如INT_MAX一類的 #define MAX 100005 #define INF 0x7FFFFFFF #define L(x) x << 1 #define R(x) x << 1 | 1 using namespace std; struct Seg_Tree { int l,r,mid; } tr[MAX*4]; int sorted[MAX]; int lef[20][MAX]; int val[20][MAX]; void build(int l,int r,int step,int x) { tr[x].l = l; tr[x].r = r; tr[x].mid = (l + r) >> 1; if(tr[x].l == tr[x].r) return ; int mid = tr[x].mid; int lsame = mid - l + 1;//lsame表示和val_mid相等且分到左邊的 for(int i = l ; i <= r ; i ++) { if(val[step][i] < sorted[mid]) { lsame --;//先假設左邊的數(mid - l + 1)個都等於val_mid,然後把實際上小於val_mid的減去 } } int lpos = l; int rpos = mid + 1; int same = 0; for(int i = l ; i <= r ; i ++) { if(i == l) { lef[step][i] = 0;//lef[i]表示[ tr[x].l , i ]區域裡有多少個數分到左邊 } else { lef[step][i] = lef[step][i-1]; } if(val[step][i] < sorted[mid]) { lef[step][i] ++; val[step + 1][lpos++] = val[step][i]; } else if(val[step][i] > sorted[mid]) { val[step+1][rpos++] = val[step][i]; } else { if(same < lsame) {//有lsame的數是分到左邊的 same ++; lef[step][i] ++; val[step+1][lpos++] = val[step][i]; } else { val[step+1][rpos++] = val[step][i]; } } } build(l,mid,step+1,L(x)); build(mid+1,r,step+1,R(x)); } int query(int l,int r,int k,int step,int x) { if(l == r) { return val[step][l]; } int s;//s表示[l , r]有多少個分到左邊 int ss;//ss表示 [tr[x].l , l-1 ]有多少個分到左邊 if(l == tr[x].l) { s = lef[step][r]; ss = 0; } else { s = lef[step][r] - lef[step][l-1]; ss = lef[step][l-1]; } if(s >= k) {//有多於k個分到左邊,顯然去左兒子區間找第k個 int newl = tr[x].l + ss; int newr = tr[x].l + ss + s - 1;//計算出新的對映區間 return query(newl,newr,k,step+1,L(x)); } else { int mid = tr[x].mid; int bb = l - tr[x].l - ss;//bb表示 [tr[x].l , l-1 ]有多少個分到右邊 int b = r - l + 1 - s;//b表示 [l , r]有多少個分到右邊 int newl = mid + bb + 1; int newr = mid + bb + b; return query(newl,newr,k-s,step+1,R(x)); } } int n,m; int main() { int T; cin >> T; int l,r,k; int ca = 1; while(T--) { scanf("%d%d",&n,&m); for(int i=1; i<=n; i++) { scanf("%d",&val[0][i]); sorted[i] = val[0][i]; } sort(sorted+1,sorted+1+n); build(1,n,0,1); printf("Case %d:\n",ca++); for(int i=0; i<m; i++) { scanf("%d%d%d",&l,&r,&k); l ++; r ++; int ll = 1; int rr = r - l + 1; int mid,maxx = 0; while(ll <= rr) { mid = (ll + rr) >> 1; if(query(l,r,mid,0,1) <= k) { maxx = max(maxx,mid); ll = mid + 1; } else rr = mid - 1; } printf("%d\n",maxx); } } return 0; }
相關推薦
HDU 4417 Super Mario (樹狀陣列+離線處理)(劃分樹+二分答案)
題意: 給定1--n區間,有q個詢問,詢問l,r,k表示區間[l,r]小於等於k的數的個數 思路: 可以用劃分樹(求區間第k大值)變形一下,來求小於等於k的個數,但是此題直接離線處理詢問高效的多。 首先將1--n區間的值記錄位置,從小到大排序,每個詢問按照k值從小到大排序,
hdu 4777 Rabbit Kingdom (樹狀陣列+離線處理)
題目連結:哆啦A夢傳送門 題意:給一串n個數字,m個詢問,每次詢問的區間中,與其他元素都互素的數字有多少個? 參考連結:https://www.cnblogs.com/kuangbin/p/3416181.html https://www.cnblogs.com/s
codeforces 703D(樹狀陣列+離線處理)
題意: 給出n個數,m次詢問,每次詢問區間 [l,r]中出現次數為偶數次的數字的異或和 思路: 如果直接求某段區間的異或和,求出來的結果實際上是出現奇數次的數字的異或和。為了求偶數次,我們可以將出現奇數次的數字變為偶數次,將出現偶數次的數字變為奇數次。所
HDU 4417 —— Super Mario(樹狀陣列,離散化,離線處理)
意思比較簡單,就是給N個數(下標從0開始),然後q個詢問,三個引數,L,R,H,詢問序列中在【L,R】這個區間上小於等於H的個數。 挺綜合的一道題目。因為數字最多100000個,數值最多達10^9,所以首先要對數值進行離散化。 像這種區間查詢問題,用S(X,H)表示從0開
HDU 4417 Super Mario(主席樹)
there mon ref seve pin ans ins Go follow Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T
hdu 4417 Super Mario (主席樹)
代碼 i++ uil 我們 php amp build iostream sort 鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 題意: 給你段長為n的序列,有q個詢問,每次詢問區間[l.r]內有多少個數小於等於k
hdu 4417 樹狀陣列 離線處理
#include <bits/stdc++.h> using namespace std; #define maxn 100000+10 int T, n, m; int sum[ma
HDU 3874 Necklace 樹狀陣列 + 離線處理
/** * 樹狀陣列 + 離線: * 看人題解的,思路: 把詢問區間[l, r]存下後按r從小到大排序 * 用陣列hash[i]記錄數字i最後一次出現的位置。用變數curR從1開始每次 * 往右掃到每個詢問區間的r。關鍵在於沒掃到新的一個數的時候,如何更新
HDU:3333 Turing Tree (樹狀陣列+離線處理+雜湊+貪心)
題意:給一個數組,每次查詢輸出區間內不重複數字的和。 思路: 用字首和的思想可以輕易求得區間的和,但是對於重複數字這點很難處理。線上很難下手,考慮離線處理。 將所有查詢區間從右端點由小到大排序,遍歷陣列中的每個數字,每次將該數字上次出現位置的值在樹狀陣列中改為0,再記錄當前
codeforces 703D 樹狀陣列 + 離線處理 + 離散化
題意:給你m個操作,每個操作求區間[l,r]中偶數個元素的異或值。 分析:根據異或的性質,偶數個的異或為0,所以我們考慮再一次元素本身,因此,偶數變成奇數,奇數變成偶數。 具體詳見程式碼:#inclu
Mishka and Interesting sum 區間異或+樹狀陣列+離線處理
知識:樹狀陣列 題意: 給你n個數,然後詢問q次,每次詢問查詢區間[l,r]裡的出現過偶數次的那些數的亦或值 解析: 首先是出現偶數次,到底是哪些數。 設Al為整個區間的異或,Odd為區間內奇數次的數的異或,Even為區間內出現偶數次的數的異或(E
(樹狀數組+離線查詢)HDU 4417 - Super Mario
blog 數組 string 個數 r++ dex 分塊 每次 class 題意: 給定一個數列,最多10萬次查詢l到r不超過h的數字的個數。 分析: 唉,太菜啦。 在線做法應該比較明顯,區間維護平衡樹,用線段樹套平衡樹,或者分塊套平衡樹,應該都能A,但是沒試
HDU 4417 Super Mario(離線線段樹or樹狀陣列)
Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability reminded in our memory. Now the poor
HDU 4417 Super Mario--離線樹狀陣列、劃分樹、線段樹
題意:詢問區間[l,r]內有幾個數字小於h 思路:對於每次詢問H,L,R,僅需要考慮比H小的hi在L,R範圍內的個數; 為了避免比H大的hi的影響,可以想到對詢問H,和hi進行排序 在詢問H時,僅將比H小的hi插入到樹狀陣列中 #include<
HDU - 4417 Super Mario 主席樹
數量 \n make In printf ons bound update ket 題意: 給一個數列$\{ a_i \}$,一些詢問$(l_i,r_i,h_i)$,求$j\in [l_i,r_i] ,a_j<=h_i$的元素數量 題解: 問區間內$<=
HDU 4417.Super Mario-無修改區間小於等於H的數的個數-可持久化線段樹
url java ios else string mes clu ber lower Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot
hdu—5976—Aninteresting game(樹狀陣列原理+特徵)
Aninteresting game Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 886 Accept
HDU-4417 Super Mario
type mario output trouble ping case hit include any Super Mario Mario is world-famous plumber. His “burly” figure and amazing jumping abi
hdu 4417 Super Mario
display view main isp case mario using font per 主席樹求區間小於某個數的數的個數模板(靜態) #include <bits/stdc++.h> using namespace std; const int
ACM-ICPC 2018 瀋陽賽區網路預賽 J. Ka Chang (分塊+樹狀陣列+dfs序)
題意 給你一顆樹,由兩種操作: 1.把這棵樹深度為 D D D的點全部都加上一個值。 2.求以p為根節點的子樹的權值和是多少? 思路 對於樹上的東西,我們可以把他求一下DFS序,之後就可以把樹上的結構變成