dlutoj 1263 树状数组

题目链接:http://acm.dlut.edu.cn/problem.php?id=1263

题目思路:树状数组,区间修改,点查询模型,现学现用的=.=,这道题算是树状数组的变形吧。。因为平常树状数组都是用来求和啥的(有很大可能是我孤陋寡闻。。),但这道题是用来进行异或操作的。。所以还得在普通的模板上进行一些小的修改

***********************************************(以下这小部分转自h t t p : / / w w w . c p p b l o g . c o m / m a t o n o 1 / a r c  h i v e / 2 0 1 1 / 0 3 / 1 9 / 1 4 2 2 2 6 . h t m l)

或者搜索:树状数组求区间和的一些常见模型,第一个就是。。

(2)“改段求点”型,即对于序列A有以下操作:

【1】修改操作:将A[l..r]之间的全部元素值加上c;

【2】求和操作:求此时A[x]的值。

这个模型中需要设置一个辅助数组B:B[i]表示A[1..i]到目前为止共被整体加了多少(或者可以说成,到目前为止的所有ADD(i, c)操作中c的总和)。

则可以发现,对于之前的所有ADD(x, c)操作,当且仅当x>=i时,该操作会对A[i]的值造成影响(将A[i]加上c),又由于初始A[i]=0,所以有A[i] = B[i..N]之和!而ADD(i, c)(将A[1..i]整体加上c),将B[i]加上c即可——只要对B数组进行操作就行了。

这样就把该模型转化成了“改点求段”型,只是有一点不同的是,SUM(x)不是求B[1..x]的和而是求B[x..N]的和,此时只需把ADD和SUM中的增减次序对调即可(模型1中是ADD加SUM减,这里是ADD减SUM加)。代码:
void  ADD( int  x,  int  c)
{
     
for  ( int  i = x; i > 0 ; i -= i & ( - i)) b[i]  +=  c;
}
int  SUM( int  x)
{
    
int  s  =   0 ;
    
for  ( int  i = x; i <= n; i += i & ( - i)) s  +=  b[i];
    
return  s;
}

操作【1】:ADD(l-1, -c); ADD(r, c);

操作【2】:SUM(x)。

                                                              

*****************************************************************************

下面是这道题的函数。。。

void update(int num,int x)
{
    for(int i=num;i>0;i-=lowbit(i))
        b[i]=b[i]^x;
}
int ans(int x)
{
    int s=0;
    for(int i=x;i<=n;i+=lowbit(i))
        s=s^b[i];
    return s;
}                                                                                                                                                               

每次更新的时候,他是把从1-num范围内的所有根节点都进行异或操作(这是第一步操作),最后算相应的值的时候就从当前位置开始,把他所有的祖先对应的值均进行异或操作就可以得出结果。。算了=。=,小松松可是天才,你要是看不懂我写的渣渣文章就自己悟去吧。。。。23333333

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 200000+1;
int num[maxn],b[maxn];
int n;
int lowbit(int x)
{
    return x&(-x);
}
void update(int num,int x)
{
    for(int i=num;i>0;i-=lowbit(i))
        b[i]=b[i]^x;
}
int ans(int x)
{
    int s=0;
    for(int i=x;i<=n;i+=lowbit(i))
        s=s^b[i];
    return s;
}
int main()
{for(int i=7;i>0;i-=lowbit(i))cout<<i<<endl;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(num,0,sizeof(num));
        memset(b,0,sizeof(b));
        int q;
        scanf("%d",&q);
        for(int i=0;i<q;i++){
            int w,a,b,c;
            scanf("%d",&w);
            if(w==1){
                scanf("%d%d%d",&a,&b,&c);
                update(a-1,c);
                update(b,c);
            }
            else{
                scanf("%d",&a);
                printf("%d\n",ans(a));
            }
        }printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值