牛客网暑期ACM多校训练营(第十场)- A - Rikka with Lowbit - (线段树 or 树状数组)

题目链接:https://www.nowcoder.com/acm/contest/148/A

题意:有函数f(x)它的值有一半概率是x - lowbit(x),一半概率是x + lowbit(x)。现在给出数组A[]对其有两种操作:①.给[L,R]区间内Ai赋值为f(A[i]);②.查询区间[L,R]内Ai和的期望。

解析:由于每个被操作的元素减和加的概率相同,所以期望值不变。直接无视操作1,直接执行操作2,问题变为简单的区间求和。

线段树代码(117ms)

#include
using namespace std;
typedef long long ll;
const ll maxN=1e5+105;
const ll mod=998244353;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
 
ll tree[maxN<<2];
ll n,m,op,x,y;
 
inline void pushup(ll rt)
{
    tree[rt]=(tree[rt<<1]+tree[rt<<1|1])%mod;
}
void build(ll l,ll r,ll rt)
{
    if(l==r)
    {
        scanf("%lld",&tree[rt]);
        return;
    }
    ll m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
ll sum(ll L,ll R,ll l,ll r,ll rt)
{
    if(L<=l&&r<=R)
    {
        return tree[rt];
    }
    ll m=(l+r)>>1;
    ll ret=0;
    if(L<=m) ret=(ret+sum(L,R,lson))%mod;
    if(R>m) ret=(ret+sum(L,R,rson))%mod;
    pushup(rt);
    return ret;
}
 
 
ll pow_mod(ll n,ll k,ll mod)//快速幂求n^k余m的结果
{
    ll res=1;
    n=n%mod;
    while(k>0)
    {
        if(k&1)
            res=res*n%mod;
        n=n*n%mod;
        k>>=1;
    }
    return res;
}
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        build(1,n,1);
        for(int i=1;i<=m;i++)
        {
            scanf("%lld%lld%lld",&op,&x,&y);
            if(op==2)
            {
                ll ans=sum(x,y,1,n,1)%mod;
                ans=ans*pow_mod(2ll,n*m,mod)%mod;
                printf("%lld\n",ans%mod);
            }
        }
    }
    return 0;
}

树状数组代码(246ms)

#include
using namespace std;
typedef long long ll;
const ll MAXN=1e5+105;
const ll mod=998244353;
 
ll n,m,op,x,y,val,tree[MAXN];
 
ll lowbit(ll i)
{
    return i&(-i);
}
void add(ll i,ll v)
{
    while(i<=n)
    {
        tree[i]=(tree[i]+v)%mod;
        i+=lowbit(i);
    }
}
ll sum(ll i)
{
    ll res=0;
    while(i>0)
    {
        res=(res+tree[i])%mod;
        i-=lowbit(i);
    }
    return res;
}
ll pow_mod(ll n,ll k,ll mod)//快速幂求n^k余m的结果
{
    ll res=1;
    n=n%mod;
    while(k>0)
    {
        if(k&1)
            res=res*n%mod;
        n=n*n%mod;
        k>>=1;
    }
    return res;
}
 
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        memset(tree,0,sizeof(tree));
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&val);
            add(i,val);
            //add(i+1,-1ll*val);
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%lld%lld%lld",&op,&x,&y);
            if(op==2)
            {
                ll ans=(sum(y)-sum(x-1)+mod)%mod;
                ans=ans*pow_mod(2ll,n*m,mod)%mod;
                printf("%lld\n",ans%mod);
            }
        }
    }
    return 0;
}

 

你可能感兴趣的:(树状数组,线段树)