poj2352 Stars 线段树单点更新

来源:互联网 发布:淘宝店如何寻找货源 编辑:程序博客网 时间:2024/06/03 23:42

题目在此:传送门

题意:在一个坐标轴上,有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;
}

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

原创粉丝点击