ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P1533 可怜的狗狗

2020-09-05 21:01:23  阅读:257  来源: 互联网

标签:ch P1533 int sum tr mid 狗狗 可怜 rc


题目背景

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

题目描述

小卡家有 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\n",b[query(root[l-1],root[r],1,t,k)]);//区间第k大的数
    }
    return 0;
}

平衡树代码:

咕咕咕

标签:ch,P1533,int,sum,tr,mid,狗狗,可怜,rc
来源: https://www.cnblogs.com/genshy/p/13617087.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有