zoukankan      html  css  js  c++  java
  • 51nod1174区间中最大的数(rmq模板或线段树 && 线段树标准模板)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1174 

    分析和思路:没什么难理解的。。(暴力就不再说了这题可以水过。。)

    rmq(本质dp)

    预处理:

    设A[i]是要求区间最值的数列,F[i, j]表示从第i个数起连续2^j个数中的最大值。(DP的状态)

    我们把F[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从 i 到i + 2 ^ (j - 1) - 1为一段,i + 2 ^ (j - 1)到i + 2 ^ j - 1为一段(长度都为2 ^ (j - 1))。用上例说明,当i=1,j=3时就是3,2,4,5 和 6,8,1,2这两段。F[i,j]就是这两段各自最大值中的最大值。于是我们得到了状态转移方程F[i, j]=max(F[i,j-1], F[i + 2^(j-1),j-1])。

    查询:

    假如我们需要查询的区间为(i,j),那么我们需要找到覆盖这个闭区间(左边界取i,右边界取j)的最小幂(可以重复,比如查询5,6,7,8,9,我们可以查询5678和6789)。

    因为这个区间的长度为j - i + 1,所以我们可以取k=log2( j - i + 1),则有:RMQ(A, i, j)=max{F[i , k], F[ j - 2 ^ k + 1, k]}。

    举例说明,要求区间[2,8]的最大值,k = log2(8 - 2 + 1)= 2,即求max(F[2, 2],F[8 - 2 ^ 2 + 1, 2]) = max(F[2, 2],F[5, 2])。

    感觉rmq就是成倍成倍的压缩空间存值,再找到递推空间关系。

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cmath>
     4 #include <cstdio>
     5 using namespace std;
     6 const int maxn=1e4+5; 
     7 int a[maxn],f[10001][15];
     8 int n,x,y;
     9 
    10 void rmq()
    11 {
    12     for(int i=1;i<=n;i++) f[i][0]=a[i];//长度为0就是本身 
    13     for(int j=1;j<=15;j++)//2的j次方<=maxn 
    14     {
    15         for(int i=1;i<=n;i++)
    16         {
    17             if(i+(1<<j)-1<=n)//从i开始长度为1<<j的,所以-1 
    18                 f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);//分成2段长度一样的,对数性质,2倍增加! 
    19         }
    20     }
    21 }
    22 
    23 int main()
    24 {
    25     cin>>n;
    26     for(int i=1;i<=n;i++) cin>>a[i];
    27     rmq();
    28     
    29     int m;
    30     cin>>m;
    31     while(m--)
    32     {
    33         cin>>x>>y;
    34         x++; y++;
    35         
    36         int k=log2(y-x+1);
    37         int ans=max(f[x][k],f[y-(1<<k)+1][k]);//将区间覆盖完全,用y减保证了不会超过 
    38         cout<<ans<<endl;
    39     }
    40     
    41     return 0;
    42 }

    线段树

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <stdio.h>
     4 using namespace std;
     5 const int maxn=1e4+5;
     6 int n,a,b,m,ans;
     7 struct node
     8 {
     9     int l,r,w,f;
    10 }tree[maxn*4];
    11 
    12 void build(int k,int ll,int rr)//建树 
    13 {
    14     tree[k].l=ll,tree[k].r=rr;
    15     if(tree[k].l==tree[k].r)
    16     {
    17         scanf("%d",&tree[k].w);
    18         return;
    19     }
    20     int m=(ll+rr)/2;
    21     build(k*2,ll,m);
    22     build(k*2+1,m+1,rr);
    23     tree[k].w=max(tree[k*2].w,tree[k*2+1].w);
    24 }
    25 
    26 void ask_interval(int k)//区间查询 
    27 {
    28     if(tree[k].l>=a&&tree[k].r<=b) 
    29     {
    30         ans=max(ans,tree[k].w);
    31         return;
    32     }
    33     int m=(tree[k].l+tree[k].r)/2;
    34     if(a<=m) ask_interval(k*2);
    35     if(b>m) ask_interval(k*2+1);
    36 }
    37 
    38 int main()
    39 {
    40     scanf("%d",&n);
    41     build(1,1,n);
    42     scanf("%d",&m);
    43     
    44     for(int i=1;i<=m;i++)
    45     {
    46         ans=0;
    47         scanf("%d%d",&a,&b);//区间查询 
    48         a++; b++;
    49         ask_interval(1);
    50         printf("%d
    ",ans);
    51     }
    52     
    53     return 0;
    54 }

     另一种有返回值参数写法

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <algorithm>
     4 using namespace std;
     5 typedef long long ll;
     6 const int maxn=1e5+5;
     7 int a[maxn];
     8 
     9 struct node
    10 {
    11     int l,r,f;
    12     ll Max;
    13 }tree[maxn*4];
    14 
    15 void build(int k,int l,int r)//建树 
    16 {
    17     tree[k].l=l; tree[k].r=r;
    18     if(l==r)
    19     {
    20         tree[k].Max=a[l];
    21         return;
    22     }
    23     else
    24     {
    25         int mid=(l+r)/2;
    26         build(k*2,l,mid);
    27         build(k*2+1,mid+1,r);
    28         tree[k].Max=max(tree[k*2].Max,tree[k*2+1].Max);
    29     }
    30 }
    31 
    32 ll query(int k,int l,int r,int posl,int posr)//区间查询 
    33 {
    34     if(l>=posl && r<=posr)  return tree[k].Max;
    35     else
    36     {
    37         ll ans1=0,ans2=0;
    38         int mid=(l+r)/2;
    39         if(posl<=mid) ans1=query(k*2,l,mid,posl,posr);
    40         if(posr>mid) ans2=query(k*2+1,mid+1,r,posl,posr);
    41         
    42         return max(ans1,ans2);
    43     }
    44 }
    45 
    46 int main()
    47 {
    48     ios::sync_with_stdio(false); cin.tie(0); 
    49     int n;
    50     cin>>n; 
    51     for(int i=1;i<=n;i++) cin>>a[i];
    52     build(1,1,n);
    53     
    54     int m;
    55     cin>>m;
    56     while(m--)
    57     { 
    58         int x,y;
    59         cin>>x>>y;
    60         
    61         ++x; ++y;
    62         cout<<query(1,1,n,x,y)<<endl;
    63     }
    64     return 0;
    65 }

    //18.10.21更新上最新线段树标准模板

    关键:不管是修改还是查询,都是从1结点(根结点全范围)往下操作 

    线段树模板1:区间加值,区间求和

    题目链接:洛谷线段树1

      1 #include <iostream>
      2 #include <string>
      3 #include <algorithm>
      4 #include <iomanip>
      5 #include <vector>
      6 #include <cstdio>
      7 #include <cstring>
      8 #include <cmath>
      9 using namespace std;
     10 typedef long long ll;
     11 typedef unsigned long long ull;
     12 const int maxn=1e5+5;
     13 ll a[maxn];
     14 ll n,m;
     15 struct px
     16 {
     17     ll l;
     18     ll r;
     19     ll w;
     20     ll f;
     21 }T[maxn*4];
     22 
     23 void push_up(ll k)
     24 {
     25     T[k].w=T[k*2].w+T[k*2+1].w;
     26 }
     27 
     28 void push_down(ll k,ll l,ll r)
     29 {
     30     if(T[k].f==0) return;
     31 
     32     ll mid=(l+r)/2;
     33                                         //1.更新和
     34     T[k*2].w=T[k*2].w+(mid-l+1)*T[k].f;//这里要*父结点的标记,因为本身可能含有其它父点的还没用的标记
     35     T[k*2+1].w=T[k*2+1].w+(r-mid-1+1)*T[k].f;
     36 
     37                             //2.下传标记
     38     T[k*2].f=T[k*2].f+T[k].f;//传左儿子标记
     39     T[k*2+1].f=T[k*2+1].f+T[k].f;//传右儿子标记
     40 
     41     T[k].f=0;//3.父结点初始化
     42 }
     43 
     44 void build(ll k,ll l,ll r)
     45 {
     46     T[k].l=l; T[k].r=r;
     47     if(l==r)
     48     {
     49         T[k].w=a[l];
     50         return;
     51     }
     52 
     53     ll mid=(l+r)/2;
     54     build(k*2,l,mid);
     55     build(k*2+1,mid+1,r);
     56 
     57     push_up(k);
     58 }
     59 
     60 void change(ll k,ll l,ll r,ll posl,ll posr,ll val)
     61 {
     62     if(posl<=l && r<=posr)
     63     {
     64         T[k].w=T[k].w+(r-l+1)*val;
     65         T[k].f=T[k].f+val;
     66         return;
     67     }
     68 
     69     push_down(k,l,r);//为了第二次及以后更新时准备,必须把上一次传下来的标记但没用的更新用掉,即是在上一次更新操作后的基础上进行这次更新才是正确答案
     70 
     71     ll mid=(l+r)/2;
     72     if(posl<=mid) change(k*2,l,mid,posl,posr,val);
     73     if(posr>=mid+1) change(k*2+1,mid+1,r,posl,posr,val);
     74 
     75     push_up(k);//父结点不传标记,直接更新一下就行
     76 }
     77 
     78 ll ask(ll k,ll l,ll r,ll posl,ll posr)
     79 {
     80     if(posl<=l && r<=posr) return T[k].w;
     81 
     82     push_down(k,l,r);//必须在查询前就完成传标记更新左右儿子,这样返回时才是修改后的正确答案
     83 
     84     ll mid=(l+r)/2;
     85     ll ls=0,rs=0,ans=0;//左儿子和,右儿子和,最终这个结点和
     86     if(posl<=mid) ls=ask(k*2,l,mid,posl,posr);
     87     if(posr>=mid+1) rs=ask(k*2+1,mid+1,r,posl,posr);
     88 
     89     ans=ls+rs;
     90     return ans;
     91 }
     92 
     93 int main()
     94 {
     95     ios::sync_with_stdio(false); cin.tie(0);
     96 
     97     cin>>n>>m;
     98     for(int i=1;i<=n;i++) cin>>a[i];
     99     build(1,1,n);
    100 
    101     while(m--)
    102     {
    103         int p;
    104         cin>>p;
    105 
    106         if(p==1)
    107         {
    108             ll x,y,k;
    109             cin>>x>>y>>k;
    110 
    111             change(1,1,n,x,y,k);//不管是修改还是查询,都是从1结点(根结点全范围)往下操作
    112         }
    113         else if(p==2)
    114         {
    115             ll x,y;
    116             cin>>x>>y;
    117 
    118             ll ans=ask(1,1,n,x,y);
    119             cout<<ans<<endl;
    120         }
    121     }
    122 
    123     return 0;
    124 }

    线段树模板2:区间加值,区间乘值,区间求和

    题目链接:洛谷P3372线段树2

      1 #include <iostream>
      2 #include <string>
      3 #include <algorithm>
      4 #include <iomanip>
      5 #include <vector>
      6 #include <cstdio>
      7 #include <cstring>
      8 #include <cmath>
      9 using namespace std;
     10 typedef long long ll;
     11 typedef unsigned long long ull;
     12 const int maxn=1e5+5;
     13 ll mod;
     14 ll a[maxn];
     15 ll n,m;
     16 struct px
     17 {
     18     ll l;
     19     ll r;
     20     ll sum;
     21     ll add;
     22     ll mul;
     23 }T[maxn*4];
     24 
     25 void push_up(ll k)
     26 {
     27     T[k].sum=(T[k*2].sum+T[k*2+1].sum)%mod;
     28 }
     29 
     30 void push_down(ll k,ll l,ll r)
     31 {
     32     if(T[k].add==0 && T[k].mul==1) return;
     33 
     34     ll mid=(l+r)/2;
     35 
     36     T[k*2].sum=T[k*2].sum*T[k].mul%mod;//1.更新和,先算乘法再算加法(因为多乘的都算到加法里面了)
     37     T[k*2].sum=(T[k*2].sum+(mid-l+1)*T[k].add)%mod;
     38     T[k*2+1].sum=T[k*2+1].sum*T[k].mul%mod;
     39     T[k*2+1].sum=(T[k*2+1].sum+(r-mid-1+1)*T[k].add)%mod;
     40 
     41 
     42     T[k*2].mul=T[k*2].mul*T[k].mul%mod;//2.下传乘标记
     43     T[k*2+1].mul=T[k*2+1].mul*T[k].mul%mod;
     44 
     45     T[k*2].add=T[k*2].add*T[k].mul%mod;//3.下传加标记(规则和更新和一样,先乘父标记再加父标记)
     46     T[k*2].add=(T[k*2].add+T[k].add)%mod;
     47     T[k*2+1].add=T[k*2+1].add*T[k].mul%mod;
     48     T[k*2+1].add=(T[k*2+1].add+T[k].add)%mod;
     49 
     50     T[k].add=0;//4.父结点标记初始化
     51     T[k].mul=1;
     52 }
     53 
     54 void build(ll k,ll l,ll r)
     55 {
     56     T[k].l=l; T[k].r=r;
     57     T[k].mul=1;
     58     if(l==r)
     59     {
     60         T[k].sum=a[l];
     61         return;
     62     }
     63 
     64     ll mid=(l+r)/2;
     65     build(k*2,l,mid);
     66     build(k*2+1,mid+1,r);
     67 
     68     push_up(k);
     69 }
     70 
     71 void change1(ll k,ll l,ll r,ll posl,ll posr,ll val)
     72 {
     73     if(posl<=l && r<=posr)
     74     {
     75         T[k].sum=T[k].sum*val%mod;
     76         T[k].mul=T[k].mul*val%mod;
     77         T[k].add=T[k].add*val%mod;
     78         return;
     79     }
     80 
     81     push_down(k,l,r);
     82 
     83     ll mid=(l+r)/2;
     84     if(posl<=mid) change1(k*2,l,mid,posl,posr,val);
     85     if(posr>=mid+1) change1(k*2+1,mid+1,r,posl,posr,val);
     86 
     87     push_up(k);
     88 }
     89 
     90 void change2(ll k,ll l,ll r,ll posl,ll posr,ll val)
     91 {
     92     if(posl<=l && r<=posr)
     93     {
     94         T[k].sum=(T[k].sum+(r-l+1)*val)%mod;
     95         T[k].add=(T[k].add+val)%mod;
     96         return;
     97     }
     98 
     99     push_down(k,l,r);
    100 
    101     ll mid=(l+r)/2;
    102     if(posl<=mid) change2(k*2,l,mid,posl,posr,val);
    103     if(posr>=mid+1) change2(k*2+1,mid+1,r,posl,posr,val);
    104 
    105     push_up(k);
    106 }
    107 
    108 ll ask(ll k,ll l,ll r,ll posl,ll posr)
    109 {
    110     if(posl<=l && r<=posr) return T[k].sum;
    111 
    112     push_down(k,l,r);
    113 
    114     ll mid=(l+r)/2;
    115     ll ls=0,rs=0,ans=0;
    116     if(posl<=mid) ls=ask(k*2,l,mid,posl,posr);
    117     if(posr>=mid+1) rs=ask(k*2+1,mid+1,r,posl,posr);
    118 
    119     ans=(ls+rs)%mod;
    120     return ans;
    121 }
    122 
    123 int main()
    124 {
    125     ios::sync_with_stdio(false); cin.tie(0);
    126 
    127     cin>>n>>m>>mod;
    128     for(int i=1;i<=n;i++) cin>>a[i];
    129     build(1,1,n);
    130 
    131     while(m--)
    132     {
    133         int p;
    134         cin>>p;
    135 
    136         if(p==1)
    137         {
    138             ll x,y,k;
    139             cin>>x>>y>>k;
    140 
    141             change1(1,1,n,x,y,k);
    142         }
    143         else if(p==2)
    144         {
    145             ll x,y,k;
    146             cin>>x>>y>>k;
    147 
    148             change2(1,1,n,x,y,k);
    149         }
    150         else if(p==3)
    151         {
    152             ll x,y;
    153             cin>>x>>y;
    154 
    155             ll ans=ask(1,1,n,x,y);
    156             cout<<ans<<endl;
    157         }
    158     }
    159 
    160     return 0;
    161 }

    线段树模板3:区间加值,区间乘值,区间求和,区间平方和

    牛客练习赛28B数据结构

      1 #include <iostream>
      2 #include <string>
      3 #include <algorithm>
      4 #include <iomanip>
      5 #include <vector>
      6 #include <cstdio>
      7 #include <cstring>
      8 #include <cmath>
      9 using namespace std;
     10 typedef long long ll;
     11 typedef unsigned long long ull;
     12 const int maxn=1e5+5;
     13 ll a[maxn];
     14 ll n,m;
     15 struct px
     16 {
     17     ll l;
     18     ll r;
     19     ll sum;
     20     ll num;
     21     ll add;
     22     ll mul;
     23 }T[maxn*4];
     24  
     25 void push_up(ll k)
     26 {
     27     T[k].sum=T[k*2].sum+T[k*2+1].sum;
     28     T[k].num=T[k*2].num+T[k*2+1].num;
     29 }
     30  
     31 void push_down(ll k,ll l,ll r)
     32 {
     33     if(T[k].add==0 && T[k].mul==1) return;
     34  
     35     ll mid=(l+r)/2;
     36  
     37     T[k*2].num=T[k*2].num*T[k].mul*T[k].mul+2*T[k*2].sum*T[k].mul*T[k].add+(mid-l+1)*T[k].add*T[k].add;
     38     T[k*2+1].num=T[k*2+1].num*T[k].mul*T[k].mul+2*T[k*2+1].sum*T[k].mul*T[k].add+(r-mid-1+1)*T[k].add*T[k].add;
     39  
     40     T[k*2].sum=T[k*2].sum*T[k].mul;
     41     T[k*2].sum=T[k*2].sum+(mid-l+1)*T[k].add;
     42     T[k*2+1].sum=T[k*2+1].sum*T[k].mul;
     43     T[k*2+1].sum=T[k*2+1].sum+(r-mid-1+1)*T[k].add;
     44  
     45  
     46     T[k*2].mul=T[k*2].mul*T[k].mul;
     47     T[k*2+1].mul=T[k*2+1].mul*T[k].mul;
     48  
     49     T[k*2].add=T[k*2].add*T[k].mul;
     50     T[k*2].add=T[k*2].add+T[k].add;
     51     T[k*2+1].add=T[k*2+1].add*T[k].mul;
     52     T[k*2+1].add=T[k*2+1].add+T[k].add;
     53  
     54     T[k].add=0;
     55     T[k].mul=1;
     56 }
     57  
     58 void build(ll k,ll l,ll r)
     59 {
     60     T[k].l=l; T[k].r=r;
     61     T[k].mul=1;
     62     if(l==r)
     63     {
     64         T[k].sum=a[l];
     65         T[k].num=a[l]*a[l];
     66         return;
     67     }
     68  
     69     ll mid=(l+r)/2;
     70     build(k*2,l,mid);
     71     build(k*2+1,mid+1,r);
     72  
     73     push_up(k);
     74 }
     75  
     76 void change1(ll k,ll l,ll r,ll posl,ll posr,ll val)
     77 {
     78     if(posl<=l && r<=posr)
     79     {
     80         //T[k*2].num=T[k*2].num*T[k].mul*T[k].mul+2*T[k*2].sum*T[k].mul*T[k].add+T[k].add*T[k].add*(mid-l+1);//原始(推出的最本质的不会错)更新照搬过来也可以,但已知这个点是乘法操作就可以化简一些(就跟求和化简加标记一样只算乘法)
     81         T[k].num=T[k].num*val*val;
     82         T[k].sum=T[k].sum*val;
     83         T[k].mul=T[k].mul*val;
     84         T[k].add=T[k].add*val;
     85         return;
     86     }
     87  
     88     push_down(k,l,r);
     89  
     90     ll mid=(l+r)/2;
     91     if(posl<=mid) change1(k*2,l,mid,posl,posr,val);
     92     if(posr>=mid+1) change1(k*2+1,mid+1,r,posl,posr,val);
     93  
     94     push_up(k);
     95 }
     96  
     97 void change2(ll k,ll l,ll r,ll posl,ll posr,ll val)
     98 {
     99     if(posl<=l && r<=posr)
    100     {
    101         T[k].num=T[k].num+2*T[k].sum*val+val*val*(r-l+1);
    102         T[k].sum=T[k].sum+(r-l+1)*val;
    103         T[k].add=T[k].add+val;
    104         return;
    105     }
    106  
    107     push_down(k,l,r);
    108  
    109     ll mid=(l+r)/2;
    110     if(posl<=mid) change2(k*2,l,mid,posl,posr,val);
    111     if(posr>=mid+1) change2(k*2+1,mid+1,r,posl,posr,val);
    112  
    113     push_up(k);
    114 }
    115  
    116 ll ask1(ll k,ll l,ll r,ll posl,ll posr)
    117 {
    118     if(posl<=l && r<=posr) return T[k].sum;
    119  
    120     push_down(k,l,r);
    121  
    122     ll mid=(l+r)/2;
    123     ll ls=0,rs=0,ans=0;
    124     if(posl<=mid) ls=ask1(k*2,l,mid,posl,posr);
    125     if(posr>=mid+1) rs=ask1(k*2+1,mid+1,r,posl,posr);
    126  
    127     ans=ls+rs;
    128     return ans;
    129 }
    130  
    131 ll ask2(ll k,ll l,ll r,ll posl,ll posr)
    132 {
    133     if(posl<=l && r<=posr) return T[k].num;
    134  
    135     push_down(k,l,r);
    136  
    137     ll mid=(l+r)/2;
    138     ll ls=0,rs=0,ans=0;
    139     if(posl<=mid) ls=ask2(k*2,l,mid,posl,posr);
    140     if(posr>=mid+1) rs=ask2(k*2+1,mid+1,r,posl,posr);
    141  
    142     ans=ls+rs;
    143     return ans;
    144 }
    145  
    146 int main()
    147 {
    148     ios::sync_with_stdio(false); cin.tie(0);
    149  
    150     cin>>n>>m;
    151     for(int i=1;i<=n;i++) cin>>a[i];
    152     build(1,1,n);
    153  
    154     while(m--)
    155     {
    156         int p;
    157         cin>>p;
    158  
    159         if(p==3)
    160         {
    161             ll x,y,k;
    162             cin>>x>>y>>k;
    163  
    164             change1(1,1,n,x,y,k);
    165         }
    166         else if(p==4)
    167         {
    168             ll x,y,k;
    169             cin>>x>>y>>k;
    170  
    171             change2(1,1,n,x,y,k);
    172         }
    173         else if(p==1)
    174         {
    175             ll x,y;
    176             cin>>x>>y;
    177  
    178             ll ans=ask1(1,1,n,x,y);
    179             cout<<ans<<endl;
    180         }
    181         else if(p==2)
    182         {
    183             ll x,y;
    184             cin>>x>>y;
    185  
    186             ll ans=ask2(1,1,n,x,y);
    187             cout<<ans<<endl;
    188         }
    189     }
    190  
    191     return 0;
    192 }

    //线段树模板4:区间异或,区间求和 

    Codeforces,242E-XOR on Segment

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #define rank ra
      5 #define pb push_back
      6 #define lson rt<<1
      7 #define rson rt<<1|1
      8 using namespace std;
      9 typedef long long ll;
     10 const int maxn=100005;
     11 int n,m;
     12 int a[maxn],sk[30];
     13 ll ans;
     14 struct node
     15 {
     16     int l,r,mid;
     17     int bit[25],lazy[25];   //bit记录每一位上1的个数 lazy为标记
     18 }t[maxn<<2];
     19 
     20 void pushup(int rt)     //pushup操作 数量直接相加即可
     21 {
     22     for(int i=1;i<=23;i++)
     23         t[rt].bit[i]=(t[lson].bit[i]+t[rson].bit[i]);
     24 }
     25 
     26 void pushdown(int rt)   //pushdown操作 反转即可
     27 {
     28     for(int i=1;i<=23;i++)
     29     {
     30         if(t[rt].lazy[i])
     31         {
     32             t[lson].bit[i]=t[lson].r-t[lson].l+1-t[lson].bit[i];
     33                 t[lson].lazy[i]^=1;
     34             t[rson].bit[i]=t[rson].r-t[rson].l+1-t[rson].bit[i];
     35                 t[rson].lazy[i]^=1;
     36             t[rt].lazy[i]=0;
     37         }
     38     }
     39 }
     40 
     41 void build(int l,int r,int rt)
     42 {
     43     int mid=(l+r)>>1;
     44     t[rt].l=l,t[rt].r=r;
     45     t[rt].mid=mid;
     46     if(l==r)
     47     {
     48         int x=a[l],g=1;
     49         while(x)    //计算数的二进制位
     50         {
     51             t[rt].bit[g++]=x%2;
     52             x=x/2;
     53         }
     54         return ;
     55     }
     56     build(l,mid,lson);
     57     build(mid+1,r,rson);
     58     pushup(rt);
     59 }
     60 
     61 void update(int l,int r,int flag,int rt)
     62 {
     63     if(l<=t[rt].l&&t[rt].r<=r)
     64     {
     65         for(int i=1;i<=23;i++)
     66         {                             //难点理解,简单例子1 1,^2助于理解
     67             //if(flag&(1<<(i-1)))     //判断哪些位需要异或 反转且标记
     68             if(flag&sk[i])            //2种写法都行,1快2好理解
     69             {
     70                 t[rt].bit[i]=t[rt].r-t[rt].l+1-t[rt].bit[i];
     71                 t[rt].lazy[i]^=1;
     72             }
     73         }
     74         return ;
     75     }
     76     pushdown(rt);
     77     if(l<=t[rt].mid)
     78         update(l,r,flag,lson);
     79     if(r>t[rt].mid)
     80         update(l,r,flag,rson);
     81     pushup(rt);
     82 }
     83 
     84 void query(int l,int r,int rt)
     85 {
     86     if(l<=t[rt].l&&t[rt].r<=r)  //计算结果
     87     {
     88         for(int i=1;i<=23;i++)
     89             ans+=(ll)t[rt].bit[i]*sk[i];
     90         return ;
     91     }
     92     pushdown(rt);
     93     if(l<=t[rt].mid)
     94         query(l,r,lson);
     95     if(r>t[rt].mid)
     96         query(l,r,rson);
     97     pushup(rt);
     98 }
     99 
    100 int main()
    101 {
    102     sk[1]=1;
    103     for(int i=2;i<=25;i++) sk[i]=2*sk[i-1];//二次方二进制初始化,常用优化操作方便好理解
    104 
    105     scanf("%d",&n);
    106     for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    107     build(1,n,1);
    108     scanf("%d",&m);
    109 
    110     int g,l,r,x;
    111     while(m--)
    112     {
    113         scanf("%d",&g);
    114         if(g==1)
    115         {
    116             ans=0;
    117             scanf("%d%d",&l,&r);
    118             query(l,r,1);
    119             cout<<ans<<endl;
    120         }
    121         else
    122         {
    123             scanf("%d%d%d",&l,&r,&x);
    124             update(l,r,x,1);
    125         }
    126     }
    127 
    128     return 0;
    129 }

    完。

  • 相关阅读:
    c# 创建多线程
    使用opencvsharp通过mvvm在image中显示图片
    c# 创建文件/文件夹对话框
    wpf MVVM框架基础
    wpf DataBinding
    layui自动点击下拉列表的一项并选中
    LayUI默认样式调整
    mysql取某个组的前n条数据
    Kali3.0系统切换中文
    JS触发某元素周围元素的样式改变
  • 原文地址:https://www.cnblogs.com/redblackk/p/9543947.html
Copyright © 2011-2022 走看看