/**
* 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));