[ JZOJ 5943 ] 树

\(\\\)

Description


  • \(n,q \le 10^5,a_i \le 10^9,k \le 2^{30},1 \le l \le r \le n\)

\(\\\)

Solution


先考虑区间与怎么搞。

注意到一个数二进制下至多只有 \(30\) 位,也就是说对这个数有效的与至多只有 \(30\) 次。

于是可以参考区间取模的想法,通过判断区间是否有冲突来决定向下递归。

这样做的复杂度需要按照每一个数至多修改 \(log\) 次算,为 \(O(nlogn)\)

怎么判区间与上一个数对当前区间是否有效?可以先到一种巧妙的方式,维护区间与,然后判断是否存在某一位,满足区间与起来的值这一位是 \(1\) ,而修改的数这一位是 \(0\)

所以关于修改只需要维护区间或。


区间和部分......

线段树每个节点维护区间和就好了吧。


区间选两个数的和的平方的期望。注意两个数可以选同一位置。

有点意思。注意平方的期望不等于期望的平方。

索性把式子拆开。

\[ E\big((x+y)^2\big)=E\big(x^2+y^2+2xy\big) \]

每一个事件概率相同,考虑从期望的定义出发。

所有事件的答案和就是

\[ \sum_{i=l}^r\sum_{j=l}^r (a_i+a_j)^2=\sum_{i=l}^r\sum_{j=l}^r a_i^2+a_j^2+2a_ia_j=\sum_{i=l}^r\sum_{j=l}^r a_i^2+\sum_{i=l}^r\sum_{j=l}^ra_j^2+\sum_{i=l}^r\sum_{j=l}^r2a_ia_j \]

发现可以再化简,得到

\[ \sum_{i=l}^r\sum_{j=l}^r a_i^2+\sum_{i=l}^r\sum_{j=l}^ra_j^2+\sum_{i=l}^r\sum_{j=l}^r2a_ia_j=2\times(r-l+1)\times\sum_{i=l}^ra_i^2+2\times (\sum_{i=l}^ra_i)^2 \]

注意到二元组的情况数显然是 \((r-l+1)^2\) 而题目答案要乘上这个值,所以不用考虑分母。

所以我们需要维护区间和和区间二次和即可。

\(\\\)

Code


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 100010
#define gc getchar
#define Rg register
#define mid ((l+r)>>1)
#define mod 998244353ll
using namespace std;
typedef long long ll;

inline ll rd(){
  ll x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}

ll n,m,a[N];

struct segment{

  ll root,ptr;

  inline ll newnode(){return ++ptr;}

  struct node{ll ls,rs,ors,sum1,sum2;}c[N<<1];

  inline void pushup(ll rt){
    c[rt].ors=c[c[rt].ls].ors|c[c[rt].rs].ors;
    c[rt].sum1=(c[c[rt].ls].sum1+c[c[rt].rs].sum1);
    c[rt].sum2=(c[c[rt].ls].sum2+c[c[rt].rs].sum2)%mod;
  }

  void build(ll &rt,ll l,ll r){
    rt=newnode();
    if(l==r){
      c[rt].ors=a[l];
      c[rt].sum1=a[l];
      c[rt].sum2=a[l]*a[l]%mod;
      return;
    }
    build(c[rt].ls,l,mid);
    build(c[rt].rs,mid+1,r);
    pushup(rt);
  }

  void del(ll rt,ll l,ll r,ll x){
    if(l==r){
      a[l]&=x;
      c[rt].ors=a[l];
      c[rt].sum1=a[l];
      c[rt].sum2=a[l]*a[l]%mod;
      return;
    }
    if((c[c[rt].ls].ors&x)!=c[c[rt].ls].ors) del(c[rt].ls,l,mid,x);
    if((c[c[rt].rs].ors&x)!=c[c[rt].rs].ors) del(c[rt].rs,mid+1,r,x);
    pushup(rt);
  }

  void updata(ll rt,ll l,ll r,ll L,ll R,ll x){
    if(l>R||r<L) return;
    if(l>=L&&r<=R){del(rt,l,r,x);return;}
    if(L<=mid) updata(c[rt].ls,l,mid,L,R,x);
    if(R>mid) updata(c[rt].rs,mid+1,r,L,R,x);
    pushup(rt);
  }

  ll query1(ll rt,ll l,ll r,ll L,ll R){
    if(l>R||r<L) return 0;
    if(l>=L&&r<=R) return c[rt].sum1;
    ll res=0;
    if(L<=mid) res+=query1(c[rt].ls,l,mid,L,R);
    if(R>mid) res+=query1(c[rt].rs,mid+1,r,L,R);
    return res;
  }

  ll query2(ll rt,ll l,ll r,ll L,ll R){
    if(l>R||r<L) return 0;
    if(l>=L&&r<=R) return c[rt].sum2;
    ll res=0;
    if(L<=mid) res+=query2(c[rt].ls,l,mid,L,R);
    if(R>mid) res+=query2(c[rt].rs,mid+1,r,L,R);
    return res%mod;
  }

}tree;

int main(){
  freopen("seg.in","r",stdin);
  freopen("seg.out","w",stdout);
  n=rd();
  for(Rg ll i=1;i<=n;++i) a[i]=rd();
  tree.build(tree.root,1,n);
  m=rd();
  for(Rg ll i=1,op,l,r,x;i<=m;++i){
    op=rd();
    if(op==1){
      l=rd(); r=rd(); x=rd();
      tree.updata(tree.root,1,n,l,r,x);
    }
    else if(op==2){
      l=rd(); r=rd();
      printf("%lld\n",tree.query1(tree.root,1,n,l,r));
    }
    else{
      l=rd(); r=rd();
      ll sum1=tree.query1(tree.root,1,n,l,r)%mod;
      ll sum2=tree.query2(tree.root,1,n,l,r);
      printf("%lld\n",(2*(r-l+1)*sum2%mod+2*sum1%mod*sum1%mod)%mod);
    }
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/SGCollin/p/9898617.html