[线段树]JZOJ 5943 树

Description

 

Input

第一行一个整数 n 表示序列长度, 接下来一行 n 个整数描述这个序列.
第三行一个整数 q 表示操作次数, 接下来 q 行每行一次操作, 格式同题目描述.

Output

       输出等同于操作 2, 3 次数之和的行数, 每行一个非负整数表示对应询问的答案. 注意操作 2 的答案不需要进行取模.
 

Sample Input

Sample Input1
5
8 4 3 5 6
5
2 3 5
3 1 2
1 2 4 3
2 3 5
3 1 2

样例 2
见下发文件中的 ex_seg2.in/out.

 

Sample Output

Sample Output1
14
608
10
384

样例 1 解释
第三次操作后, 序列变为 [8, 0, 3, 1, 6].

 
 

Data Constraint

对于前 30% 的数据, n, q ≤ 100;
对于另 20% 的数据, 没有操作 1;
对于另 20% 的数据, 没有操作 3;
对于 100% 的数据, n, q ≤ 10^5, ai ≤ 10^9, k ≤ 2^30, 1 ≤ l ≤ r ≤ n.

分析

不修改应该都会吧,就是线段树

然后带修改,我们可以把每次要and的数和该区间的或和and一次,如果没有变化可以不进行这次修改

然后可以证明一个数最多减小logn次

那么暴力修改即可

 

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll P=998244353;
const int N=1e5+10;
ll sqr[4*N],sum[4*N],_or[4*N];
ll a[N];
int n,q;

void Build(int x,int l,int r) {
    if (l==r) {
        sqr[x]=a[l]*a[l]%P;sum[x]=a[l];_or[x]=a[l];
        return;
    }
    int mid=l+r>>1;
    Build(x<<1,l,mid);
    Build((x<<1)+1,mid+1,r);
    sqr[x]=(sqr[x<<1]+sqr[(x<<1)+1])%P;
    sum[x]=sum[x<<1]+sum[(x<<1)+1]; 
    _or[x]=_or[x<<1]|_or[(x<<1)+1];
}

void Pushdown(int x,int l,int r,ll k) {
    if (_or[x]==(_or[x]&k)) return;
    if (l==r) {
        a[l]&=k;sqr[x]=a[l]*a[l]%P;sum[x]=a[l];_or[x]=a[l];
        return;
    }
    int mid=l+r>>1;
    Pushdown(x<<1,l,mid,k);
    Pushdown((x<<1)+1,mid+1,r,k);
    sqr[x]=(sqr[x<<1]+sqr[(x<<1)+1])%P;
    sum[x]=sum[x<<1]+sum[(x<<1)+1];
    _or[x]=_or[x<<1]|_or[(x<<1)+1];
}

void Change(int x,int l,int r,int lll,int rr,ll k) {
    if (l>rr||lll>r) return;
    if (_or[x]==(_or[x]&k)) return;
    if (lll<=l&&r<=rr) {
        Pushdown(x,l,r,k);
        return;
    }
    int mid=l+r>>1;
    if (lll<=mid) Change(x<<1,l,mid,lll,rr,k);
    if (mid<rr) Change((x<<1)+1,mid+1,r,lll,rr,k);
    sqr[x]=(sqr[x<<1]+sqr[(x<<1)+1])%P;
    sum[x]=sum[x<<1]+sum[(x<<1)+1];
    _or[x]=_or[x<<1]|_or[(x<<1)+1];
}

ll Query_sqr(int x,int l,int r,int lll,int rr) {
    if (l>rr||lll>r) return 0;
    if (lll<=l&&r<=rr) return sqr[x];
    int mid=l+r>>1;
    ll ans=0;
    if (lll<=mid) ans=Query_sqr(x<<1,l,mid,lll,rr)%P;
    if (mid<rr) (ans+=Query_sqr((x<<1)+1,mid+1,r,lll,rr))%=P;
    return ans;
}

ll Query_sum(int x,int l,int r,int lll,int rr) {
    if (l>rr||lll>r) return 0;
    if (lll<=l&&r<=rr) return sum[x];
    int mid=l+r>>1;
    ll ans=0;
    if (lll<=mid) ans=Query_sum(x<<1,l,mid,lll,rr);
    if (mid<rr) ans+=Query_sum((x<<1)+1,mid+1,r,lll,rr);
    return ans;
}

int main() {
    freopen("seg.in","r",stdin);
    freopen("seg.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    Build(1,1,n);
    scanf("%d",&q);
    while (q--) {
        int order,l,r;
        scanf("%d%d%d",&order,&l,&r);
        if (order==1) {
            ll k;scanf("%lld",&k);
            Change(1,1,n,l,r,k);
        }
        else
        if (order==2) printf("%lld\n",Query_sum(1,1,n,l,r));
        else {
            ll a=Query_sqr(1,1,n,l,r),b=Query_sum(1,1,n,l,r)%P;
            printf("%lld\n",(a*2ll*(r-l+1)%P+b*b*2ll%P)%P);
        }
    }
}
View Code

 

posted @ 2018-11-03 16:49  Vagari  阅读(126)  评论(0编辑  收藏  举报