首页 > 其他分享 >CF-242-E-线段树

CF-242-E-线段树

时间:2024-01-20 20:15:31浏览次数:35  
标签:int 线段 tr cin CF 242 bit

242-E 题目大意

给定一个长为\(n\)的数组\(a\),\(q\)次操作,操作分两种:
\(1.l,r\):输出\({\sum_{i=l}^{r}a_i}\)。
\(2.l,r,x\):把区间\([l,r]\)中的元素都异或上\(x\)。


Solution

区间信息具有可并性,线段树能够快速得到所求区间的信息。

线段树节点中维护一个数组\(bit\),\(bit[i]\)表示当前区间\([l,r]\)中有多少个元素第\(i\)为\(1\),合并的过程把两个子节点的\(bit\)暴力合并即可。

操作二用懒标记维护即可,时间复杂度\(O(nlognlogU)\),\(U\)为最大元素的二进制长度。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

const int N=1e5+10;
struct node{
    int l,r,tag;
    vector<int> bit;
}tr[N<<2];

void pushup(int u){
    for(int i=22;~i;i--){
        tr[u].bit[i]=tr[u<<1].bit[i]+tr[u<<1|1].bit[i];
    }
}

void pushdown(int u){
    if(tr[u].tag){
        tr[u<<1].tag^=tr[u].tag;
        tr[u<<1|1].tag^=tr[u].tag;
        for(int i=22;~i;i--){
            if(tr[u].tag&(1<<i)){
                tr[u<<1].bit[i]=tr[u<<1].r-tr[u<<1].l+1-tr[u<<1].bit[i];
                tr[u<<1|1].bit[i]=tr[u<<1|1].r-tr[u<<1|1].l+1-tr[u<<1|1].bit[i];
            }
        }
        tr[u].tag=0;
    }
}

void build(int u,int l,int r,vector<int> &a){
    tr[u]={l,r,0};
    tr[u].bit.resize(23);
    if(l==r){
        for(int i=22;~i;i--){
            if(a[l-1]&(1<<i)){
                tr[u].bit[i]=1;
            }
        }
        return;
    }
    int m=(l+r)>>1;
    build(u<<1,l,m,a);
    build(u<<1|1,m+1,r,a);
    pushup(u);
}

void modify(int u,int l,int r,int k){
    if(l<=tr[u].l&&tr[u].r<=r){
        tr[u].tag^=k;
        for(int i=22;~i;i--){
            if(k&(1<<i)){
                tr[u].bit[i]=tr[u].r-tr[u].l+1-tr[u].bit[i];
            }
        }
        return;
    }
    pushdown(u);
    int m=(tr[u].l+tr[u].r)>>1;
    if(l<=m) modify(u<<1,l,r,k);
    if(r>m) modify(u<<1|1,l,r,k);
    pushup(u);
}

ll query(int u,int l,int r){
    if(l<=tr[u].l&&tr[u].r<=r){
        ll res=0;
        for(int i=22;~i;i--){
            res+=1LL*(1<<i)*tr[u].bit[i];
        }
        return res;
    }
    pushdown(u);
    ll res=0;
    int m=(tr[u].l+tr[u].r)>>1;
    if(l<=m) res+=query(u<<1,l,r);
    if(r>m) res+=query(u<<1|1,l,r);
    return res;
}

void solve(){
    int n;
    cin>>n;
    vector<int> a(n);
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    build(1,1,n,a);
    int q;
    cin>>q;
    while(q--){
        int op,l,r,k;
        cin>>op>>l>>r;
        if(op&1){
            cout<<query(1,l,r)<<'\n';
        }else{
            cin>>k;
            modify(1,l,r,k);
        }
    }
}

int main(){
    ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }
    return 0;
}

标签:int,线段,tr,cin,CF,242,bit
From: https://www.cnblogs.com/fengxue-K/p/17977054

相关文章

  • CF1850B
    签到题,按照题意模拟即可。遍历整个数组,当$a_i\le10$时,用\(b_i\)更新最大值即可。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;signedmain(){intT,n,a,b,ans,mx;cin>>T;while(T--){mx=0;ans......
  • CF1850C
    要找到这个单词,就要先找到这个单词的开头,在输入时即可判断。根据题意,保持列数不变,增加行数,直到不为字母,输出途经的字母即构成了单词。#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;chara[9][9];signedmain(){intT,x,y,pd;cin>>T;......
  • CF1850F
    不难想到,可以枚举每个\(a_i\)的倍数,并用一个数组统计出现次数,最后求最大值,理论时间复杂度\(O(n\logn)\)。但如果\(a_i\)较小且重复出现,可能退化到\(O(n^2)\)。因此可以做一个小优化:对于每个\(a_i\len\),提前统计出每个数出现的次数,枚举倍数时只计算一次,可以提升计算效率......
  • CF1850D
    根据题意,不难想到贪心,将\(a\)从小到大排序,使得相邻两数之差的绝对值尽可能小。若存在两数之差的绝对值大于\(k\),则将两数之间作为一个“分界线”。在确定所有“分界线”后,序列被分成了多个子段,这些子段中最多保留一个才能满足条件。根据贪心,选择保留最长的一段,用\(n\)减去其......
  • CF1763C
    Updateon2023.8.17:修正了一处小错误。分析题目可知,答案至少为\(\sum_{i=1}^{n}a_i\)。接下来考虑怎样使答案更大。可以对\(n\)分成如下几类情况讨论:\(n=2\)这种情况十分简单,如果选择操作最多一次,否则两次就会变为\(0\)。用$\left|a_1-a_2\right|\times2$判......
  • CF1569C
    这题是个分类讨论题。要使得没有人连续两次提议,关键在于最大值和次大值。因此分三类情况。记最大值为\(a\),出现次数\(cnta\),次大值\(b\),出现次数\(cntb\)。\(cnta\ge2\)最大值不止一个,说明有多个人会同时在第\(a\)轮结束,因此无论任何情况都不会有人连续两次提议。......
  • CF1712A
    看完题目,很容易得知要使$\sum\limits_{i=1}^kp_i$最小,且\(p_i\)是\(n\)的一个排列,可以知道最终的答案为\(\sum\limits_{i=1}^ki\)。现在我们考虑如何将原序列转化成答案序列。得知答案后,我们要做的就是将所有的\(p_i\lek\)移到序列的前\(k\)位中。暴力枚举序列的......
  • CF1760A
    题意\(T\)组数据,每组数据给\(3\)个数,要求选出既不是最大值也不是最小值的那个数。做法这题由于十分简单,因此各种做法均可通过。最朴素的做法为比较出最大值和最小值,然后对三个数依次判断,找出符合条件的那个数即可。Code#include<iostream>#include<cstdio>usingnames......
  • CF1760C
    题意\(T\)组数据,每组数据给定一个长度为\(n\)的序列\(s\)。求出每个数与最大值的差(最大值本身除外),以及最大值和次大值的差(最大值的位置),按照原来的顺序输出。做法模拟题,十分简单,只需对原序列求最大值和次大值即可,然后再按位置输出。Code具体实现细节见代码。#include<io......
  • CF1760B
    题意\(T\)组数据,每次给定一个只含小写字母的字符串,求要拼出这个句子至少需要长度为多少的字母表。定义长度为\(x\)的字母表含有\(26\)字母表上的前\(x\)个字母。做法转化一下题目,很容易发现题目本质上就是要求字符串中最大的字母在\(26\)字母表中的位置。其它不是最大......