leetcode 1109 线段树

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
 #define ll long long
 typedef struct node
 {
     int left;
     int right;
     ll sum;
     ll lazy_tag;
 }node;
 void build_tree(node* tree,int index,int left,int right)
 {
     tree[index].left=left;
     tree[index].right=right;
     tree[index].sum=0;
     tree[index].lazy_tag=0;
     if(left==right)
     return;
     build_tree(tree,2*index,left,(left+right)>>1);
     build_tree(tree,2*index+1,((left+right)>>1)+1,right);
 }
 void add1(node* tree,int index,int add_left,int add_right,int x)//查找要加的区间,回溯时父结点sum值改变
                                                                //类似区间查询
 {
     if(add_left>tree[index].right||add_right<tree[index].left)
     {
         return;
     }
      if(add_left<=tree[index].left&&add_right>=tree[index].right)//第index个结点对应的区间满足要求
      {
            tree[index].lazy_tag+=x;
            tree[index].sum+=(tree[index].right-tree[index].left+1)*x;
            return;
      }
      add1(tree,2*index,add_left,add_right,x);
      add1(tree,2*index+1,add_left,add_right,x);
      tree[index].sum=tree[2*index].sum+tree[2*index+1].sum;
 }
  void add2(node* tree,int index,int add_left,int add_right,int x)//查找要加的区间,回溯时父结点sum值改变
                                                                //类似区间查询
 {
      if(add_left<=tree[index].left&&add_right>=tree[index].right)//第index个结点对应的区间满足要求
      {
            tree[index].lazy_tag+=x;
            tree[index].sum+=(tree[index].right-tree[index].left+1)*x;
            return;
      }
      int mid=(tree[index].left+tree[index].right)>>1;
      if(mid<add_left)
      {
          add2(tree,(index<<1)+1,add_left,add_right,x);
      }
      else if(mid>=add_right)
      {
          add2(tree,(index<<1),add_left,add_right,x);
      }
      else
      {
          add2(tree,(index<<1),add_left,mid,x);
          add2(tree,(index<<1)+1,mid+1,add_right,x);
      }
      tree[index].sum=tree[2*index].sum+tree[2*index+1].sum;
 }
 void change(node* tree,int index)//如果结点index的lazy_tag不为0,则把lazy_tag下放到它的子节点 然后把该结点的tag清0
 {
     if(tree[index].lazy_tag!=0)
     {
         if(tree[index].left!=tree[index].right)
         {
         tree[index<<1].lazy_tag+=tree[index].lazy_tag;
         tree[(index<<1)+1].lazy_tag+=tree[index].lazy_tag;
         tree[index<<1].sum+=(tree[index<<1].right-tree[index<<1].right+1)*tree[index].lazy_tag;
         tree[(index<<1)+1].sum+=(tree[(index<<1)+1].right-tree[(index<<1)+1].left+1)*tree[index].                               lazy_tag;
         }
         tree[index].lazy_tag=0;
     }
 }
 int query_x(node* tree,int index,int x)//端点查询x
 {
      change(tree,index);
      if(tree[index].left==tree[index].right)
      {
          return tree[index].sum;
      }
      int mid=(tree[index].left+tree[index].right)>>1;
      if(mid<x)
      {
          return query_x(tree,2*index+1,x);
      }
      else
      {
          return query_x(tree,2*index,x);
      }
 }                           
int* corpFlightBookings(int** bookings, int bookingsSize, int* bookingsColSize, int n, int* returnSize){
    int* answer=(int*)malloc(n*sizeof(int));
    *returnSize=n;
    node tree[4*n+1];
    memset(tree,0,sizeof(tree));
    build_tree(tree,1,1,n);
    for(int i=0;i<bookingsSize;i++)
    {
        add2(tree,1,bookings[i][0],bookings[i][1],bookings[i][2]);
    }
    for(int i=0;i<n;i++)
    {
        answer[i]=query_x(tree,1,i+1);
    }
    return answer;
}

其中add1与add2是add的两种写法,时间上差距不大,在leetcode上测试 add2最多比add1少8ms
但是用线段树做时间复杂度比较大

差分数组
官方题解
注意到一个预订记录实际上代表了一个区间的增量。我们的任务是将这些增量叠加得到答案。因此,我们可以使用差分解决本题。

差分数组对应的概念是前缀和数组,对于数组 [1,2,2,4][1,2,2,4],其差分数组为 [1,1,0,2][1,1,0,2],差分数组的第 ii 个数即为原数组的第 i-1i−1 个元素和第 ii 个元素的差值,也就是说我们对差分数组求前缀和即可得到原数组。

差分数组的性质是,当我们希望对原数组的某一个区间 [l,r][l,r] 施加一个增量\textit{inc}inc 时,差分数组 dd 对应的改变是:d[l]d[l] 增加 \textit{inc}inc,d[r+1]d[r+1] 减少 \textit{inc}inc。这样对于区间的修改就变为了对于两个位置的修改。并且这种修改是可以叠加的,即当我们多次对原数组的不同区间施加不同的增量,我们只要按规则修改差分数组即可。

在本题中,我们可以遍历给定的预定记录数组,每次 O(1)O(1) 地完成对差分数组的修改即可。当我们完成了差分数组的修改,只需要最后求出差分数组的前缀和即可得到目标数组。

注意本题中日期从 11 开始,因此我们需要相应的调整数组下标对应关系,对于预定记录 \textit{booking}=[l,r,\textit{inc}]booking=[l,r,inc],我们需要让 d[l-1]d[l−1] 增加 \textit{inc}inc,d[r]d[r] 减少 \textit{inc}inc。特别地,当 rr 为 nn 时,我们无需修改 d[r]d[r],因为这个位置溢出了下标范围。如果求前缀和时考虑该位置,那么该位置对应的前缀和值必定为 00。读者们可以自行思考原因,以加深对差分数组的理解。

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/corporate-flight-bookings/solution/hang-ban-yu-ding-tong-ji-by-leetcode-sol-5pv8/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
 #define ll long long
int* corpFlightBookings(int** bookings, int bookingsSize, int* bookingsColSize, int n, int* returnSize){
    int* ans=(int*)malloc(n*sizeof(int));
    *returnSize=n;
    memset(ans,0,n*sizeof(int));
    for(int i=0;i<bookingsSize;i++)
    {
        ans[bookings[i][0]-1]+=bookings[i][2];
        if(bookings[i][1]<n)
        {
            ans[bookings[i][1]]-=bookings[i][2];
        }
    }
    for(int i=1;i<n;i++)
    {
        ans[i]+=ans[i-1];
    }
    return ans;
}

注意当用memset初始化ans数组时候
memset(ans,0,sizeof(ans));不行
要用memset(ans,0,n*sizeof(int));

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值