nowcoder 211E - 位元運算?位元運算! - [二進位線段樹][與或線段樹]

來源:互聯網
上載者:User

標籤:shu   格式   支援   運算   build   資料   typedef   樹節點   沒有   

題目連結:https://www.nowcoder.com/acm/contest/211/E

題目描述

請實現一個資料結構支援以下操作:區間迴圈左右移,區間與,區間或,區間求和。

 

輸入描述:

第一行n,q表示數列長度及操作次數。
第二行n個數表示初始序列。
接下來q行表示操作。

操作格式如下:
一行表示一個操作。所有操作形如 opt l r v。
opt=1 表示將區間[l,r]迴圈右移v位。
opt=2 表示將區間[l,r]迴圈左移v位。
opt=3 表示將區間[l,r]按位或上v。
opt=4 表示將區間[l,r]按位與上v。
opt=5 詢問區間[l,r]的和。

保證opt=1或2時 1 ≤ v ≤ 20
注意:為了最佳化你的做題體驗,操作5也會輸入一個v,但是是沒有意義的。
注意:迴圈左右移在20個二進位位的意義下進行

輸出描述:

對於每個opt=5的操作,輸出一個數表示答案。

輸入
10 10
10112 23536 1305 7072 12730 29518 12315 3459 12435 29055
4 5 10 12373
2 1 6 7
5 4 10 24895
1 1 4 8
5 3 7 7767
5 7 9 6127
4 2 8 30971
5 4 10 2663
1 7 10 1
1 2 9 5

輸出
2001530
1600111
24611
49482

備忘:
1 ≤ N,Q ≤ 2*10^5 且 0 ≤ ai < 2^20
一些說明:
1. 對於00000000000000000101,右移一位後會變成10000000000000000010
2. 不是區間位移,是區間中的每一個數的二進位位的位移

 

題解:

(說實話這道題其實不難的,會線段樹就應該想到怎麼做的,可能是我腦子太笨了吧,比賽的時候想不到怎麼做。)

考慮到只有二進位下只有 $20$ 位,而且修改操作都是按位與或者按位或,所以可以將 $20$ 位拆開來看。

然後就簡單了呀:

  對 $01$ 序列中某一個區間,全部與上 $x(x=0,1)$,那麼 $x = 1$ 時不變, $x = 0$ 時全 $0$。

  對 $01$ 序列中某一個區間,全部或上 $x(x=0,1)$,那麼 $x = 0$ 時不變, $x = 1$ 時全 $1$。(這兩種操作可以歸結為直接把一個常見的線段樹區間覆蓋操作)

  迴圈平移就是在 $20$ 棵平衡樹進行資料的迴圈平移,向左向右迴圈平移都可以全部歸結為向右平移,範圍為 $(0,19)$,這個就是把每個線段樹節點裡的二十位的01序列重新排一下即可。

  求和,我們線段樹每個節點都有一個 $val[20]$ 用以為維護某一位上,當前區間內所有數字在這一位上合起來總共出現了多少個 $1$,也就是說這個 $val[20]$ 相當於一個算加法但還沒來得及進位的位元,這樣的位元轉成十進位和普通位元轉十進位是一樣的。

 

AC代碼:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int maxn=2e5+10;int n,q,a[maxn];/********************************* Segment Tree - st *********************************/int tmp[20];struct Node{    int l,r;    int val[20];    int lazy[20],shft;    void upd_shft(int x)    {        x=(x+20)%20;        shft=(shft+x)%20;        for(int i=0;i<x;i++) tmp[i]=lazy[i];        for(int i=0;i<20-x;i++) lazy[i]=lazy[i+x];        for(int i=0;i<x;i++) lazy[i+20-x]=tmp[i];        for(int i=0;i<x;i++) tmp[i]=val[i];        for(int i=0;i<20-x;i++) val[i]=val[i+x];        for(int i=0;i<x;i++) val[i+20-x]=tmp[i];    }    void upd_lazy(int i,int x)    {        val[i]=(r-l+1)*x;        lazy[i]=x;    }}node[4*maxn];void pushdown(int root){    if(node[root].shft)    {        node[root*2].upd_shft(node[root].shft);        node[root*2+1].upd_shft(node[root].shft);        node[root].shft=0;    }    for(int i=0;i<20;i++)    {        if(node[root].lazy[i]!=-1)        {            node[root*2].upd_lazy(i,node[root].lazy[i]);            node[root*2+1].upd_lazy(i,node[root].lazy[i]);            node[root].lazy[i]=-1;        }    }}void pushup(int root){    for(int i=0;i<20;i++)        node[root].val[i]=node[root*2].val[i]+node[root*2+1].val[i];}void build(int root,int l,int r){    if(l>r) return;    node[root].l=l, node[root].r=r;    node[root].shft=0;    for(int i=0;i<20;i++) node[root].lazy[i]=-1;    if(l==r)    {        for(int i=0;i<20;i++)            node[root].val[i]=(a[l]>>i)%2;    }    else    {        int mid=(l+r)/2;        build(root*2,l,mid);        build(root*2+1,mid+1,r);        pushup(root);    }}void update(int type,int root,int st,int ed,int x){    if(st<=node[root].l && node[root].r<=ed)    {        if(type==1)        {            node[root].upd_shft(x);        }        if(type==2)        {            for(int i=0,k;i<20;i++)            {                k=(x>>i)%2;                if(!k) node[root].upd_lazy(i,0);            }        }        if(type==3)        {            for(int i=0,k;i<20;i++)            {                k=(x>>i)%2;                if(k) node[root].upd_lazy(i,1);            }        }    }    else    {        int mid=(node[root].l+node[root].r)/2;        pushdown(root);        if(st<=mid) update(type,root*2,st,ed,x);        if(ed>mid) update(type,root*2+1,st,ed,x);        pushup(root);    }}ll query(int root,int st,int ed){    if(st<=node[root].l && node[root].r<=ed)    {        ll res=0;        for(int i=0;i<20;i++) res+=(ll)node[root].val[i]*(1<<i);        return res;    }    pushdown(root);    int mid=(node[root].l+node[root].r)/2;    ll res=0;    if(st<=mid) res+=query(root*2,st,ed);    if(ed>mid) res+=query(root*2+1,st,ed);    return res;}/********************************* Segment Tree - ed *********************************/int main(){    scanf("%d%d",&n,&q);    for(int i=1;i<=n;i++) scanf("%d",&a[i]);    build(1,1,n);    while(q--)    {        int op,l,r,v;        scanf("%d%d%d%d",&op,&l,&r,&v);        if(op==1) update(1,1,l,r,v);        if(op==2) update(1,1,l,r,-v);        if(op==3) update(3,1,l,r,v);        if(op==4) update(2,1,l,r,v);        if(op==5) printf("%lld\n",query(1,l,r));    }}

 

nowcoder 211E - 位元運算?位元運算! - [二進位線段樹][與或線段樹]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.