HDOJ 4417: Super Mario

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417


题意:
给定一个序列,
每次询问[l,r]区间内<=x的元素的个数


算法:
本题解法非常多。
以后我会慢慢补全这篇文章,
当做一次基础数据结构训练。


划分树 (218ms)

#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
const int MAXN=110000;
int tr[MAXN<<2];
int sorted[MAXN],toleft[20][MAXN],val[20][MAXN];

void build(int l, int r, int dep, int rt) {
    if(l==r) {
        return;
    }
    int mid=(l+r)>>1;
    int lnum=mid-l+1;
    for(int i=l; i<=r; i++) {
        if(val[dep][i]<sorted[mid]) {
            lnum--;
        }
    }
    int lp=l,rp=mid+1;
    int cur_lnum=0;
    for(int i=l; i<=r; i++) {
        if(i==l) {
            toleft[dep][i]=0;
        } else {
            toleft[dep][i]=toleft[dep][i-1];
        }
        if(val[dep][i]<sorted[mid]) {
            toleft[dep][i]++;
            val[dep+1][lp++]=val[dep][i];
        } else if(val[dep][i]>sorted[mid]) {
            val[dep+1][rp++]=val[dep][i];
        } else {
            if(cur_lnum<lnum) {
                cur_lnum++;
                toleft[dep][i]++;
                val[dep+1][lp++]=val[dep][i];
            } else {
                val[dep+1][rp++]=val[dep][i];
            }
        }
    }
    build(l,mid,dep+1,rt<<1);
    build(mid+1,r,dep+1,rt<<1|1);
}

int query(int l, int r, int L, int R, int x, int dep, int rt) {
    if(l==r) {
        return val[dep][l]<=x;
    }
    int lnum,cur_lnum,rnum,cur_rnum;
    int mid=(l+r)>>1;
    if(l==L) {
        lnum=toleft[dep][R];
        cur_lnum=0;
    } else {
        lnum=toleft[dep][R]-toleft[dep][L-1];
        cur_lnum=toleft[dep][L-1];
    }
    if(sorted[mid]>x) {
        if(!lnum) {
            return 0;
        }
        int newL=l+cur_lnum;
        int newR=l+lnum+cur_lnum-1;
        return query(l,mid,newL,newR,x,dep+1,rt<<1);
    } else {
        int rnum=R-L+1-lnum;
        int cur_rnum=L-l-cur_lnum;
        if(!rnum) {
            return lnum;
        }
        int newL=mid+cur_rnum+1;
        int newR=mid+cur_rnum+rnum;
        return lnum+query(mid+1,r,newL,newR,x,dep+1,rt<<1|1);
    }
}

int main() {
    int cas;
    scanf("%d",&cas);
    for(int T=1; T<=cas; T++) {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++) {
            scanf("%d",&val[0][i]);
            sorted[i]=val[0][i];
        }
        sort(sorted,sorted+n);
        build(0,n-1,0,1);
        printf("Case %d:\n",T);
        while(m--) {
            int l,r,x;
            scanf("%d%d%d",&l,&r,&x);
            printf("%d\n",query(0,n-1,l,r,x,0,1));
        }
    }
    return 0;
}


划分树+二分 (562ms)

#include<cstdio>
#include<iostream>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
const int MAXN=110000;
int tr[MAXN<<2];
int sorted[MAXN],toleft[20][MAXN],val[20][MAXN];

void build(int l, int r, int dep, int rt) {
    if(l==r) {
        return;
    }
    int mid=(l+r)>>1;
    int lnum=mid-l+1;
    for(int i=l; i<=r; i++) {
        if(val[dep][i]<sorted[mid]) {
            lnum--;
        }
    }
    int lp=l,rp=mid+1;
    int cur_lnum=0;
    for(int i=l; i<=r; i++) {
        if(i==l) {
            toleft[dep][i]=0;
        } else {
            toleft[dep][i]=toleft[dep][i-1];
        }
        if(val[dep][i]<sorted[mid]) {
            toleft[dep][i]++;
            val[dep+1][lp++]=val[dep][i];
        } else if(val[dep][i]>sorted[mid]) {
            val[dep+1][rp++]=val[dep][i];
        } else {
            if(cur_lnum<lnum) {
                cur_lnum++;
                toleft[dep][i]++;
                val[dep+1][lp++]=val[dep][i];
            } else {
                val[dep+1][rp++]=val[dep][i];
            }
        }
    }
    build(l,mid,dep+1,rt<<1);
    build(mid+1,r,dep+1,rt<<1|1);
}

int query(int l, int r, int L, int R, int k, int dep, int rt) {
    if(l==r) {
        return val[dep][l];
    }
    int lnum,cur_lnum,rnum,cur_rnum;
    int mid=(l+r)>>1;
    if(l==L) {
        lnum=toleft[dep][R];
        cur_lnum=0;
    } else {
        lnum=toleft[dep][R]-toleft[dep][L-1];
        cur_lnum=toleft[dep][L-1];
    }
    if(lnum>=k) {
        int newL=l+cur_lnum;
        int newR=l+lnum+cur_lnum-1;
        return query(l,mid,newL,newR,k,dep+1,rt<<1);
    } else {
        int rnum=R-L+1-lnum;
        int cur_rnum=L-l-cur_lnum;
        int newL=mid+cur_rnum+1;
        int newR=mid+cur_rnum+rnum;
        return query(mid+1,r,newL,newR,k-lnum,dep+1,rt<<1|1);
    }
}

int main() {
    int cas;
    scanf("%d",&cas);
    for(int T=1; T<=cas; T++) {
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0; i<n; i++) {
            scanf("%d",&val[0][i]);
            sorted[i]=val[0][i];
        }
        sort(sorted,sorted+n);
        build(0,n-1,0,1);
        printf("Case %d:\n",T);
        while(m--) {
            int x,llim,rlim;
            scanf("%d%d%d",&llim,&rlim,&x);
            int l=0,r=rlim-llim+1;
            while(l<r) {
                int mid=(l+r+1)>>1;
                if(query(0,n-1,llim,rlim,mid,0,1)<=x) {
                    l=mid;
                } else {
                    r=mid-1;
                }
            }
            printf("%d\n",l);
        }
    }
    return 0;
}


主席树(125ms)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;

const int MAXN = 110000;
const int MAXM = 2100000;
int tot;

typedef struct
{
    int cot, right, left;
} NODE;

int root[MAXN],a[MAXN];
vector<int> hash;
NODE node[MAXM];

int newnode(int cot, int left, int right)
{
    node[tot].cot = cot;
    node[tot].left = left;
    node[tot].right = right;
    return tot ++;
}

int insert(int rt, int l, int r, int k)
{
    if(l <= k && k <=r)
    {
        if(l == r)
        {
            return newnode(node[rt].cot + 1, 0, 0);
        }
        int mid = (l + r) >> 1;
        return newnode(node[rt].cot + 1,
                       insert(node[rt].left, l, mid, k),
                       insert(node[rt].right, mid + 1, r, k));
    }
    return rt;
}

int query(int p, int q, int l, int r, int k)
{
    if(hash[r] <= k)
    {
        return node[q].cot - node[p].cot;
    }
    if(l == r)
    {
        return 0;
    }
    int mid = (l + r) >> 1;
    int ret = query(node[p].left, node[q].left, l, mid, k);
    if(k >= hash[mid+1])
    {
        ret += query(node[p].right, node[q].right, mid + 1, r, k);
    }
    return ret;
}

int main()
{
    int cas;
    scanf("%d", &cas);
    for(int T = 1; T <= cas; T ++)
    {
        int n, q;
        scanf("%d %d", &n, &q);
        tot=0;
        root[0]=newnode(0, 0, 0);
        hash.clear();
        for(int i = 1; i <= n; i ++)
        {
            scanf("%d", &a[i]);
            hash.push_back(a[i]);
        }
        sort(hash.begin(), hash.end());
        hash.erase(unique(hash.begin(), hash.end()), hash.end());
        int m = hash.size();
        for(int i = 1; i <= n; i ++)
        {
            a[i] = lower_bound(hash.begin(), hash.end(), a[i]) - hash.begin();
            root[i] = insert(root[i - 1], 0, m - 1, a[i]);
        }
        printf("Case %d:\n",T);
        while(q --)
        {
            int l, r, k;
            scanf("%d %d %d",&l, &r, &k);
            printf("%d\n", query(root[l], root[r + 1], 0, m - 1, k));
        }
    }
    return 0;
}



你可能感兴趣的:(HDOJ 4417: Super Mario)