题解 | #[NOIP2004]合唱队形#

数星星 Stars

https://ac.nowcoder.com/acm/problem/50428

题目中的坐标给出序列是一个很好的序列。因为我们只需要找该点左下角的星星,那么后面给出的点必然不符合左下角的设定,所以只需要判断给出该点之前有多少个星星在其左下角。更准确的说,只需要判断多少个星星的x坐标<=当前星星的x坐标即可。

不会树状数组,还没学。用线段树写了一遍,还是比较基础的。

主要思路就是对于每一个读入的点,搜索一遍x坐标组成的线段树中有多少个区间在他之前即可。比如读入的x坐标为7,假设之前读入的x坐标区间[1,10],那么第一个点的区间就是[1,10],然后依次往下二分成左右子树区间,显然[1,5],[6,7]为最终找到的组成答案的区间。加起来即可。

具体看代码,代码中有注释吧。

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e4 + 5e3 + 7,rr=3e4+2e3+7;//rr表示的是x的最大坐标,也就是所构建的线段树的最大区间的端点值。
int ans[N],n,x,y,cnt=0,tmp=0,val[rr<<2];//val表示区间的值,应该开rr*4的大小,因为区间最大的端点值就是x的最大坐标值。
void serch(int p,int l,int r,int x)
{
    if (r <= x)//判断条件应当是r<=x的时候,l不用判,因为只考虑某个区间在x的左边即可。
    {
        tmp += val[p]; return;
    }
    int mid = l + r >> 1;
    serch(p << 1,l,mid,x);//左边区间必搜
    if (x >= mid + 1)serch(p<<1|1,mid+1,r,x);//右边区间需要判断x是否在这个区间
}
void build(int p,int l,int r,int x)
{
    if (l==r)//代表找到了x这个点
    {
        val[p]++;
        return;
    }
    int mid = l + r >> 1;
    if (x <= mid)build(p << 1, l, mid, x);
    else build(p << 1 | 1, mid + 1, r, x);
    val[p] = val[p << 1] + val[p << 1 | 1];//回溯赋值
}
int main()
{
    cin >> n;
    for (int i=1;i<=n;i++)
    {
        tmp = 0;//这是不考虑0的等级。每次要清零。
        scanf("%d%d",&x,&y);
        if (x == 0) { ans[cnt++]++; continue;}//此处用于特判x=0的情况,cnt表示x=0的星星的个数
        serch(1,1,rr,x);
        ans[tmp + cnt]++;//要额外考虑cnt,所以这里是tmp+cnt
        build(1,1,rr,x);
    }
    for (int i = 0; i < n; i++)printf("%d\n",ans[i]);
    return 0;
}

那么就让我们一起愉快地AC吧~

全部评论
因为不能包括他自己这个点,所以是先搜索serch,再插入建树build
点赞 回复 分享
发布于 2023-11-13 16:24 湖南

相关推荐

frutiger:逆天,我家就安阳的,这hr咋能说3k的,你送外卖不比这工资高得多?还说大厂来的6k,打发叫花子的呢?这hr是怎么做到说昧良心的话的
点赞 评论 收藏
分享
叶扰云倾:进度更新,现在阿里云面完3面了,感觉3面答得还行,基本都答上了,自己熟悉的地方也说的比较细致,但感觉面试官有点心不在焉不知道是不是不想要我了,求阿里收留,我直接秒到岗当阿里孝子,学校那边的房子都退租了,下学期都不回学校,全职猛猛实习半年。这种条件还不诱人吗难道 然后现在约到了字节的一面和淘天的复活赛,外加猿辅导。华为笔试完没动静。 美团那边之前投了个base广州的,把我流程卡麻了,应该是不怎么招人,我直接简历挂了,现在进了一个正常的后端流程,还在筛选,不知道还有没有hc。
点赞 评论 收藏
分享
评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务