poj2352 Stars 线段树单点更新

题目在此:传送门

题意:在一个坐标轴上,有n颗星星,每颗星都有等级,等级的范围为0~n-1,每颗星的等级为它左下角存在的星星(不包括自身,y坐标可以相等)的数量,有几颗星等级就为几,然后依次输出等级0~n-1的星的数量;

思路:线段树,因为是要判断左下角星星的数量,那么我们先以y坐标升序排序,如果y坐标相同就以x坐标升序排序,这样就能保证我们判断一个星星的等级时,它左下角的所有点都已经放入线段树中;排序题目已经帮助我们完成,那么就是线段树该如何存点。线段树只用来存每颗星星的x坐标,因为y是升序的关系,我们能保证区间查询某个星星时所有的点都在该星星下方,这时我们只需要判断x坐标是否比查询的星星的x坐标小就可以了;

附上代码:

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<vector>
#include<cstdio>
#include<set>
#define MAXN 15005
#define maxn 32005//坐标的最大值
#define INF 1000000007
#define lmid l,m,rt<<1
#define rmid m+1,r,rt<<1|1
using namespace std;
int tree[maxn<<2];
struct node
{
   int x,y;
   int dj;//每颗星星的等级
}s[MAXN];
int ans[MAXN];//每个等级星星的数量
void pushup(int rt)
{
   tree[rt]=tree[rt<<1]+tree[rt<<1|1];
}
void build(int l,int r,int rt)
{
   if(l==r)
   {
      tree[rt]=0;
      return ;
   }
   int m=(l+r)>>1;
   build(lmid);
   build(rmid);
   pushup(rt);
}
void update(int L,int C,int l,int r,int rt)
{
   if(l==r)
   {
      tree[rt]+=C;//个数加1
      return ;
   }
   int m=(l+r)>>1;
   if(L<=m) update(L,C,lmid);
   else update(L,C,rmid);
   pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
   if(l>=L&&R>=r)

   {
      return tree[rt];
   }
   int m=(l+r)>>1;
   int res=0;
   if(m>=L) res+=query(L,R,lmid);
   if(R>m) res+=query(L,R,rmid);
   return res;
}
int main()
{
   memset(ans,0,sizeof(ans));
   int n;
   scanf("%d",&n);
   int m=0;
   for(int i=0;i<n;i++)
   {
      scanf("%d%d",&s[i].x,&s[i].y);
      s[i].dj=0;
      m=max(m,s[i].x);
   }
   build(0,m,1);
   for(int i=0;i<n;i++)
   {
      if(i&&s[i].x==s[i-1].x&&s[i].y==s[i-1].y)
      {
         s[i].dj=s[i-1].dj;
         ans[s[i].dj]++;
      }
      else {
         s[i].dj=query(0,s[i].x,0,m,1);
         ans[s[i].dj]++;
      }
      update(s[i].x,1,0,m,1);
   }
   for(int i=0;i<n;i++)
      cout<<ans[i]<<endl;
   return 0;
}

有到题与此题类似,可做练习题传送门

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值