1. 程式人生 > >HDU 4417 Super Mario (樹狀陣列+離線處理)(劃分樹+二分答案)

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序,之後就可以把樹上的結構變成