poj 2352 Stars (线段树#4/树状数组)

本质上是维护一个表,每次改变一个元素的值,然后求前i个元素的和。

法一:线段树

      我本来是想每个叶节点表示从1到该节点位置的元素和,插入一个元素,那么它后面的节点的值都要加一,这便是操作区间。可是我这样是复杂化了,无限WA。

     其实就是简单的求和问题,每个节点维护一个sum值就好了。

   代码:454ms

   

#include <cstdio>
#include <cstring>
using namespace std;

#define N 15009 
#define L 32010 


struct node{
       int l, r;
       int val;
    }Tree[L * 5];
///

int n;
int level[N];

void build(int l, int r, int x)
{
     Tree[x].l = l;
     Tree[x].r = r;
     Tree[x].val = 0;
     if (l == r)return;
     int mid = (l + r) / 2;
     build(l, mid, x * 2);
     build(mid + 1, r, x * 2 + 1);
}



void update(int nu,  int x)
{
       if (Tree[x].l <= nu && nu <= Tree[x].r)
       {
                Tree[x].val++; 
       }
       if (Tree[x].l == Tree[x].r)return; 
       int mid = (Tree[x].l + Tree[x].r) / 2;
       if (mid < nu)update(nu, x * 2 + 1);
       else if (mid >= nu)update(nu,  x * 2);
} 



int find(int l, int r,  int x)
{ 
       if (Tree[x].l == l && Tree[x].r == r)
       {
                     return Tree[x].val;
       }
       int mid =  (Tree[x].l + Tree[x].r) / 2;
       if (mid < l)return find(l, r, x * 2 + 1);
       if (mid >= r)return find(l, r, x * 2);
       return find(l, mid, x * 2) + find(mid + 1, r, x * 2 + 1); 
}
   

 


int main()
{
   // FILE* fp = fopen("in.txt", "r"); 
    scanf(  "%d", &n); 
    build(0, L, 1);
    for (int i = 0; i < n; i++) level[i] = 0;
    int x, y; 
    for (int i = 0; i < n; i++)
    {
          scanf( "%d %d", &x, &y);
          level[find(0, x, 1)]++;
          update(x, 1); 
    }
    for (int i = 0; i < n; i++)
         printf("%d\n", level[i]); 
  //  getchar();
    return 0;
} 



法二:树状数组

       树状数组应用范围较窄,“改变一个元素,求前i个元素的和”。

     391ms

   

#include <cstdio>
#include <cstdlib>
#include <cstring> 
using namespace std;
#define N 32010
    int n, c[N], level[N];

inline int lowbit(int x)
{
      return x & (-x);
}

int sum(int x)
{
     int ans = 0;
     while (x > 0)
     {
           ans += c[x];
           x -= lowbit(x);
     } 
     return ans;
} 

void update(int i)
{
     while (i <= N)
     {
           c[i] ++;
           i += lowbit(i);
     } 
}
 
int main()
{
      int x, y;
      scanf("%d", &n);
      memset(c, 0, sizeof(c));
      memset(level, 0, sizeof(level)); 
      for (int i = 0; i < n; i++)
      {
            scanf("%d %d", &x, &y);
            level[sum(x + 1)]++;
            update(x + 1);
      }
      for (int i = 0; i < n; i++)printf("%d\n", level[i]);
     // scanf("%d", &n); 
      return 0;
} 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值