Super Mario(主席樹+權值線段樹)

題目:添加鏈接描述
思路:先把數據離散化,按照權值建立主席樹,然後對於一個高度h,我們找的答案是區間中不大於h的數,那麼我們求取了mid後,如果h大於mid,那麼左子樹的數都小於h所以要統計左子樹的上的數量,然後繼續遞歸求解右子樹,一直下去直到葉節點,返回它的值就ok,還有就是我們查詢的高度也是離散化之後的高度。upper_bound找的時候不要找飄了

#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cstdio>
#define mod (10007)
#define middle (l+r)>>1
#define SIZE 1000000+5
#define lowbit(x) (x&(-x))
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long ll;
typedef long double ld;
const int inf_max = 0x3f3f3f;
const ll Linf = 9e18;
const int maxn = 100000+100;
const long double E = 2.7182818;
const double eps=0.0001;
using namespace std;
inline int read()
{
    int f=1,res=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { res=res*10+ch-'0' ; ch=getchar(); }
    return f*res;
}
struct node
{
    int l,r,val;
}tree[maxn * 25];
int lsan[maxn],m,cnt,root[maxn],n,a[maxn],number = 1;

int getid(int x,int up) {
    return lower_bound(lsan + 1,lsan + 1 + up,x) - lsan;
}
void update(int l,int r,int &now,int last,int v) {
    tree[++cnt] = tree[last]; tree[cnt].val++; now=cnt; //建立主席樹,順帶按照權值維護一下每個數的個數
    if(l == r) return ;
    int mid = middle;
    if(v <= mid) update(l,mid,tree[now].l,tree[last].l,v);
    else update(mid + 1,r,tree[now].r,tree[last].r,v);
}
int query(int l,int r,int l_rt,int r_rt,int k) {
    if(r <= k ) return tree[r_rt].val-tree[l_rt].val;  //整個左區間的數都不大於k 所以我們直接返回統計的數量,不需要遞歸
    if(l == r) return tree[r_rt].val - tree[l_rt].val;
    int mid = middle;
    if(k <= mid) return query(l,mid,tree[l_rt].l,tree[r_rt].l,k); //去左區間找
    else return query(mid + 1,r,tree[l_rt].r,tree[r_rt].r,k) + tree[tree[r_rt].l].val - tree[tree[l_rt].l].val;  //去右區間找,同時加上左區間的。
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        cnt = 0;
        memset(lsan,0,sizeof(lsan));
        memset(root,0,sizeof(root));
        memset(tree,0,sizeof(tree));
        scanf("%d%d",&n,&m);
        for(int i = 1;i <= n ;i++) scanf("%d",&a[i]),lsan[i] = a[i];
        sort(lsan + 1,lsan + 1 + n);
        int tot = unique(lsan + 1,lsan + 1 + n) - lsan - 1;
        for(int i = 1;i <= n; ++i) {
            update(1,tot,root[i],root[i-1],getid(a[i],tot));
        }
        printf("Case %d:\n",number++);
        for(int i = 1;i <= m; ++i) {  //這裏m我寫成了n,re10多次,艹
            int ql,qr,up;
            scanf("%d%d%d",&ql,&qr,&up);
            ql++;qr++;
            int pos = upper_bound(lsan+1,lsan+1+tot,up)-lsan;
           // printf("pos=%d\n",pos);
            if(pos == 1) { printf("0\n"); continue; }
            else if(pos > tot) { printf("%d\n",qr + 1 - ql); continue; }
            else
                printf("%d\n",query(1,tot,root[ql-1],root[qr],pos-1));
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章