【组队排位赛 #1】 Fenwick Tree 利用树状数组的运算法则

Input file: fenwick.in
Output file: fenwick.out
Time limit: 3 seconds
Memory limit: 256 megabytes
Fenwick tree is a data structure effectively supporting prefix sum queries.
For a number t denote as h(t) maximal k such that t is divisible by 2k
. For example, h(24) = 3, h(5) = 0.
Let l(t) = 2h(t)
, for example, l(24) = 8, l(5) = 1.
Consider array a[1], a[2], . . . , a[n] of integer numbers. Fenwick tree for this array is the array
b[1], b[2], . . . , b[n] such that
b[i] = X
i
j=i−l(i)+1
a[j].
So
b[1] = a[1],
b[2] = a[1] + a[2],
b[3] = a[3],
b[4] = a[1] + a[2] + a[3] + a[4],
b[5] = a[5],
b[6] = a[5] + a[6],

For example, the Fenwick tree for the array
a = (3, −1, 4, 1, −5, 9)
is the array
b = (3, 2, 4, 7, −5, 4).
Let us call an array self-fenwick if it coincides with its Fenwick tree. For example, the array above is not
self-fenwick, but the array a = (0, −1, 1, 1, 0, 9) is self-fenwick.
You are given an array a. You are allowed to change values of some elements without changing their
order to get a new array a
′ which must be self-fenwick. Find the way to do it by changing as few elements
as possible.
Input
The first line of the input file contains n — the number of elements in the array (1 ≤ n ≤ 100 000). The
second line contains n integer numbers — the elements of the array. The elements do not exceed 109 by
their absolute values.
Output
Output n numbers — the elements of the array a

. If there are several solutions, output any one.
Example
fenwick.in fenwick.out
6
3 -1 4 1 -5 9
0 -1 1 1 0 9

题意:给一个串,问尽量修改少一点元素,使得原数组每个元素和其树状数组每个元素对应相等

思路(树状数组规律):

1.首先,得清楚树状数组存储的规则。如下图,就是题目中给的:
在这里插入图片描述
(理解了树状数组本身运算规则的可以跳过下面一段)
1.首先要清楚的运算规则是每个b[i]存储的是区间【i-lowbit(i)+1,i】内的元素,但是当前的b[i]的子树只包含b[i-2k], 其中2k<lowbit(i)。也就是能对b[i]产生直接影响的,不是区间内的所有b[j]。如直接对c[8]有贡献的是c[4] , c[6], c[7],当然还有自身的a[8],上述即是c[8-22],c[8-21],c[8-20] ,其中k<4 。就是这个意思

如下图:
在这里插入图片描述

2.按照题意,我们可以将上述表示成
c[1] = a[1]
c[2] = a[1] + a[2] = a[2]
等等,到这里发现,a[1]只能为0,不然不满足等式
接着
c[3] = a[3]
其实奇数的话【i-lowbit(i)+1,i】就只有自己。
c[4] = a[1] + a[2] + a[3] + a[4] = a[4] ===>a[3] = -(a[1]+a[2])
c[5] = a[5]
c[6] = a[5] + a[6] = a[6] -->a[5] = 0 。
c[7] = a[7]
c[8] = (这里写成上面说的)c[4] + c[6] + c[7] + a[8] = a[8]
那么,顺理成章 c[7] = a[7] = -(c[4]+c[6])。

到此,我们发现,只要是奇数位(如7), 那么它的lowbit(i)+1的点,其实就是i+1的点(如8)的子树中( 即上面的c[4] + c[6] + c[7] ),除去当前i和i+1元素后的相反数( 就是 -(c[4]+c[6] ),就是我这个奇数位要变成的值,才能使得等式平衡。至于修改其他位可不可以,当然可以,但不是最少的步数,毕竟奇数位的话c[i]就只包含一个元素,只需要修改它就行了。那么规律就在这了。但是我们怎么知道i+1的所有子树呢?如果还记得树状数组的最值单点更新,那么就非常简单了,一个方法
就是上面说到的枚举找b[i-2k]就行了,其中2k<lowbit(i)。(还不理解的话继续拿上面7、的例子看)那么查询这一步就是logn的时间复杂度,最后枚举所有奇数位就是总共(n/2)logn的时间复杂度。

em。。还不理解的话见代码注释

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <queue>
#include <limits.h>
#define maxn 100000+500
using namespace std;
typedef long long ll;
ll a[maxn];     //a用来存题给数组
ll c[maxn];     //c就是树状数组
ll n;

ll lowbit(ll x)     //lowbit函数
{
    return x&(-x);
}

int main()
{
    freopen("fenwick.in","r",stdin);
    freopen("fenwick.out","w",stdout);
    while(~scanf("%lld",&n))
    {
        memset(a,0,sizeof(a));
        memset(c,0,sizeof(c));
        for(ll i=1;i<=n;i++)  scanf("%lld",&a[i]);
        for(ll i=1; i<n; i++)       //注意最后一个点不要算进去,WA了4次
        {
               if(i%2==0)  continue;        //只判断奇数位
               ll len = lowbit(i+1);   //找到后面那个元素的【lowbit(i+1)+1,i+1】区间
               ll tmp = 0;
               for(ll j=2;j<len;j <<= 1)        //枚举2^k
               {
                    tmp +=  a[i+1-j];       //因为这里c就是a(题目要求嘛),所以前面算过的a就代表当前子树(子区间),累加
               }
               a[i] = -tmp;     //当前这个位就是累加和的相反数
        }
        for(ll i=1;i<=n;i++)
        {
            if(i<n)
            printf("%lld ",a[i]);
            else
            printf("%lld\n",a[i]);
        }
    }

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值