• POJ 2761 Feed the dogs(树状数组求区间第K大)


    题目链接: 戳我

    题目大意:Jiajia要为宠物狗,宠物狗按成一排站好(1 < i <= n),第 i 只狗的喜欢程度是 a[i], 之后他会先喂某个区间内第k个

    即 n 个数, m个询问,接着是 n个数

    接下来 m 行,每行是 l r k即 l 到 r 这个区间第 k 小的数,每个询问输出一个答案,即 a[i]

    求区间第k大有很多算法, 详见此博客 【数据结构练习】 求区间第K大数的几种方法

    我用的树状数组解法,来自 

    树状数组从前往后求和,用来解第k大(或小)的数 poj 2985 The k-th Largest Group

    代码:

    //Author LJH
    //www.cnblogs.com/tenlee
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <map>
    #define clc(a, b) memset(a, b, sizeof(a))
    using namespace std;
    
    const int inf = 0x3f;
    const int INF = 0x3f3f3f3f;
    const int maxn = 1e6+5;
    
    struct Que
    {
        int l, r, k, id;
        bool operator < (const Que &a) const 
        {
            if(l == a.l) return r < a.r;
            return l < a.l;
        }
    }q[maxn];
    
    struct Dog
    {
        int val, id;
        bool operator < (const Dog &a) const 
        {
            return val < a.val;
        }
    }d[maxn];
    
    int node[maxn], ans[maxn], fval[maxn], pval[maxn], n, m;
    
    inline int lowbit(int x)
    {
        return x & -x;
    }
    void Init()
    {
        clc(node, 0);
    }
    
    void add(int x, int val)
    {
        //printf("x = %d
    ", x);
        if(x == 0) return;
        while(x <= n)
        {
            node[x] += val;//记录这个结点下面包含了多少个数,即这个结点总共有多少个叶子结点
            x += lowbit(x);
        }
    }
    
    int findkth(int k)//查找第k大的数,返回第几个数,即排序后的下标
    {
        int i, cnt = 0, ans = 0;
        for(i = 20; i >= 0; i--) //二进制思想
        {
            ans += (1 << i);
            if(ans >= n || cnt + node[ans] >= k) ////这里大于等于k的原因是可能大小为ans的数不在c[ans]的控制范围之内,所以这里求的是 < k
                ans -= (1 << i);
            else 
                cnt += node[ans];
            //cnt用来累加比当前ans小的总组数
        }
        //求出的ans是累加和(即小于等于ans的数的个数)小于k的情况下ans的最大值,所以ans+1就是第k大的数
        return ans + 1;
    }
    
    int main()
    {
        int i, j;
        while(~scanf("%d %d", &n, &m))
        {
            Init();
            for(i = 1; i <= n; i++)
            {
                scanf("%d", &d[i].val);
                d[i].id = i;
            }
            sort(d+1, d+n+1);
            int k = 1;
            fval[d[1].id] = 1;
            pval[1] = d[1].val;
            for(i = 2; i <= n; i++)
            {
                if(d[i].val != d[i-1].val)
                    pval[++k] = d[i].val; //消除重复的
                fval[d[i].id] = k; //记录这个数是排序后第几个数, 即原来的第几个数对应现在排序后的第几个数
            }
            for(i = 0; i < m; i++)
            {
                scanf("%d %d %d", &q[i].l, &q[i].r, &q[i].k);
                q[i].id = i;
                if(q[i].r < q[i].l) swap(q[i].l, q[i].r);
            }
            sort(q, q+m);
    
            int curl = 1, curr = 0; //左右 初始化左比右大
            for(i = 0; i < m; i++)
            {
                if(curr < q[i].l)// curl curr q[i].l q[i].r
                {
                    for(j = curl; j <= curr; j++)//fval[j] 获得 原来第j个数在排序后的坐标
                        add(fval[j], -1); //清空上次查询,即把树状数组不属于该区间的设为0, 下同
                    for(j = q[i].l; j <= q[i].r; j++)
                        add(fval[j], 1);
                    curl = q[i].l; curr = q[i].r;
                }
                else // curl q[i].l curr q[i].r || q[i].l curl curr q[i].r
                {
                    for(j = curl; j < q[i].l; j++) // 清空上次查询,就是把不属于对应区间的 值改为0
                        add(fval[j], -1);
                    for(j = curr+1; j <= q[i].r; j++)
                        add(fval[j], 1);
                    curl = q[i].l; curr = q[i].r;
                }
                ans[q[i].id] = pval[findkth(q[i].k)];
            }
            for(int i = 0; i < m; i++)
                printf("%d
    ", ans[i]);
        }
        return 0;
    }
    

    划分树代码:

    #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;
        int n, m;
        while(~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);
            while(m--)
            {
                int l,r,k;
                scanf("%d%d%d",&l,&r,&k);
                l--;
                r--;
                printf("%d
    ",query(0,n-1,l,r,k,0,1));
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    第五单元 shell编程 摩天居士
    第六单元 磁盘阵列与逻辑卷 摩天居士
    第七单元 文件查找与文件特殊权限 摩天居士
    第三单元 文件压缩与磁盘管理 摩天居士
    第二单元 文件和用户管理 摩天居士
    shell编程获取服务器资产信息 摩天居士
    第四单元 正则表达式与软件包管理 摩天居士
    欧姆龙CXOne4.31启动仿真报错 因为计算机中丢失OSLicence.dll。尝试重新安装该程序...
    VS2019 使用QT插件导入项目时导入失败 Please look in the output above for errors and warnings.
    qt5 断开 lambad槽
  • 原文地址:https://www.cnblogs.com/tenlee/p/4564505.html
Copyright © 2020-2023  润新知