• P1533 可怜的狗狗


    Link

    题目背景

    小卡由于公务需要出差,将新家中的狗狗们托付给朋友嘉嘉,但是嘉嘉是一个很懒的人,他才没那么多时间帮小卡喂狗狗。

    题目描述

    小卡家有 N 只狗,由于品种、年龄不同,每一只狗都有一个不同的漂亮值。漂亮值与漂亮的程度成反比(漂亮值越低越漂亮),吃饭时,狗狗们会按顺序站成一排等着主人给食物。

    可是嘉嘉真的很懒,他才不肯喂这么多狗呢,这多浪费时间啊,于是他每次就只给第i只到第j只狗中第k漂亮的狗狗喂食(好狠心的人啊)。而且为了保证某一只狗狗不会被喂太多次,他喂的每个区间(i,j)不互相包含。

    输入格式

    第一行输入两个数n,m,你可以假设n<300001 并且 m<50001;m表示他喂了m 次。

    第二行n个整数,表示第i只狗的漂亮值为ai。

    接下来m行,每行3个整数i,j,k表示这次喂食喂第i到第j只狗中第k漂亮的狗的漂亮值。

    输出格式

    M行,每行一个整数,表示每一次喂的那只狗漂亮值为多少。

    输入输出样例

    输入 #1

    7 2
    1 5 2 6 3 7 4
    1 5 3
    2 7 1
    

    输出 #1

    3
    2
    

    题解

    一句话题意:区间第 (k) 大数

    这道题的做法有很多种,比如说平衡树加双指针或者裸的主席树。

    由于蒟蒻我不会写平衡树(那只能用主席树水过去了)。

    还是口胡一下平衡树的做法吧。

    因为他的询问区间不重叠,所以我们可以给询问区间按左端点拍一下序。

    搞两个指针像莫队一样来回反复横跳,每次在平衡树中删除或加入一个数。

    再用平衡树求解区间第 (k) 大数。

    至于线段树的做法,就是裸的主席树啦(以后会把主席树的坑补上的)。

    主席树Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 3e5+10;
    int n,m,l,r,tot,k,cnt;
    int root[N*22],a[N],b[N];
    inline int read()
    {
        int s = 0,w = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
        return s * w;
    } 
    struct node
    {
        int lc,rc,sum;
    }tr[N*22];
    int build(int l,int r)//建空树
    {
        int p = ++tot;
        if(l == r)
        {
            tr[p].sum = 0;
            return p;
        }
        int mid = (l+r)>>1;
        tr[p].lc = build(l,mid);
        tr[p].rc = build(mid+1,r);
        return p;
    }
    int insert(int now,int L,int R,int x,int val)//新开一个版本
    {
        int p = ++tot;
        tr[p].lc = tr[now].lc;//先继承上一个版本的状态
        tr[p].rc = tr[now].rc;
        tr[p].sum = tr[now].sum;
        if(L == R)
        {
            tr[p].sum += val;
            return p;
        }
        int mid = (L + R)>>1;
        if(x <= mid)//递归改左儿子
        {
            tr[p].lc = insert(tr[now].lc,L,mid,x,val);
        }
        if(x > mid)//递归右儿子
        {
            tr[p].rc = insert(tr[now].rc,mid+1,R,x,val);
        }
        tr[p].sum = tr[tr[p].lc].sum + tr[tr[p].rc].sum;//up 一下
        return p;
    }
    int query(int p,int q,int L,int R,int k)//区间第 k 大的数
    {
        if(L == R){return L;}//如果 L== R 就说明我们已经找到了答案
        int mid = (L + R)>>1;
        int tmp = tr[tr[q].lc].sum - tr[tr[p].lc].sum;
        if(k <= tmp)// k 和 tmp 一定不要写反了 我在这里卡了好几回
        {
            return query(tr[p].lc,tr[q].lc,L,mid,k);
        } 
        if(k > tmp)
    	{
    		return query(tr[p].rc,tr[q].rc,mid+1,R,k-tmp);
    	}
    }
    int main()
    {
        n = read(); m = read();
        for(int i = 1; i <= n; i++)
        {
            a[i] = read();
            b[++cnt] = a[i];
        }
        sort(b+1,b+cnt+1);//先离散化一下
        int t = unique(b+1,b+cnt+1)-b-1;
        for(int i = 1; i <= n; i++)
        {
            a[i] = lower_bound(b+1,b+t+1,a[i])-b;
        }
        root[0] = build(1,n); //建立一个空树
        for(int i = 1; i <= n; i++)
        {
            root[i] = insert(root[i-1],1,n,a[i],1);//依次把每个版本插进去
        }
        for(int i = 1; i <= m; i++)
        {
            l = read(); r = read(); k = read();
            printf("%d
    ",b[query(root[l-1],root[r],1,t,k)]);//区间第k大的数
        }
        return 0;
    }
    

    平衡树代码:

    咕咕咕

  • 相关阅读:
    零售数据框架
    API安全Checklist
    高级区块链工程师评定
    软件项目复杂性
    e-Commerce电商参考云架构
    面试中的学习能力判断
    SpringCloud微服务架构案例-共享服务中心
    Software Architecture and High Level Design软件架构与概要设计
    基于Istio的ServiceMesh
    a store with that domain name already exists怎么解决
  • 原文地址:https://www.cnblogs.com/genshy/p/13617087.html
Copyright © 2020-2023  润新知