线段树/学会分析每个数值最多被修改的次数

You are given an array of N integers. You should support the following queries on this array.

  • 0 L R : Find the minimum integer in the range AL, AL+1, ..., AR.
  • 1 L R X : You should apply the assignment A[i] = A[i] & X, for all indices i in range [L, R], where & denotes bitwise AND operation.

 

Input

First line of the input contains two space separated integers N and Q.

Second line contains N integer numbers denoting array A.

In the next Q lines, each contain one of the queries described above.

Output

For each query of the type 0, output a single line containing the answer of the query.

Constraints

  • 1 ≤ N, Q ≤ 105
  • 1 ≤ AiX ≤ 109
  • 1 ≤ L ≤ R ≤ N

Example

Input:
5 5
1 5 2 3 4
0 2 5
1 1 5 6
0 2 2
1 2 5 3
0 1 3

Output:
2
4
0


题目描述
给定长度为 N 的整数序列。你需要支持如下操作:
• 0 L R:查询序列在区间 [L, R] 中的最小值;
• 1 L R X:对于序列在区间 [L, R] 中的每个元素 Ai,执行操作:Ai ← Ai&X,其中 & 为按 位与操作。

分析
区间查询最小值可以用线段树,这道题麻烦的是更新操作,若是对区间里每个数都按位与一遍,必定会超时。这时不要慌,稳定分析,
&按位与有个特点,即该数的二进制表示为某位为0的话,此后的所以更新,都不会改变该位为0的事实。这样我们可以计算这个区间究竟
最多能进行多少次&操作?即区间内每个数的每个对应位上1的总数,若某次进行&x操作时,检测一下会不会对区间造成影响,若不会,
就此打住,这样就避免了许多无用操作,不必每次都更新到叶子结点上。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include <queue>
#include <vector>
#include<bitset>
#include<map>
#include<deque>
using namespace std;
typedef long long LL;
const int maxn = 1e5+5;
const int mod = 77200211+233;
typedef pair<int,int> pii;
#define X first
#define Y second
#define pb push_back
//#define mp make_pair
#define ms(a,b) memset(a,b,sizeof(a))
const int inf = 0x3f3f3f3f;
#define lson l,m,2*rt
#define rson m+1,r,2*rt+1

struct node{
    int a;
    int l,r;
    int st;
    int mid(){
        return (l+r)>>1;
    }
}tree[maxn<<2];

void pushup(int rt){
    tree[rt].a = min(tree[rt<<1].a,tree[rt<<1|1].a);
    tree[rt].st = tree[rt<<1].st | tree[rt<<1|1].st;
}

void build(int l,int r,int rt){
    tree[rt].l=l,tree[rt].r=r;
    if(l==r){
        scanf("%d",&tree[rt].a);
        tree[rt].st=tree[rt].a;
        return;
    }
    int m=tree[rt].mid();
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushup(rt);
}

void update(int l,int r,int x,int rt){
    if(l<= tree[rt].l && r>= tree[rt].r){
        int t = tree[rt].st&x;
        if(t==tree[rt].st) return;
    }
    if(tree[rt].l==tree[rt].r){
        tree[rt].a = tree[rt].a & x;
        tree[rt].st=tree[rt].a;
        return;
    }
    int m = tree[rt].mid();
    if(l<=m) update(l,r,x,rt<<1);
    if(r>m) update(l,r,x,rt<<1|1);

    pushup(rt);
}

int query(int l,int r,int rt){
    if(l<= tree[rt].l && r>= tree[rt].r){
        return tree[rt].a;
    }
    int m=tree[rt].mid();
    int ans=inf;
    if(l<=m) ans=min(ans,query(l,r,rt<<1));
    if(r>m) ans=min(ans,query(l,r,rt<<1|1));
    return ans;
}

int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        build(1,n,1);

        while(m--){
            int x,l,r;
            scanf("%d",&x);
            if(x){
                int l,r;
                scanf("%d%d%d",&l,&r,&x);
                update(l,r,x,1);
            }else{
                scanf("%d%d",&l,&r);
                cout<<query(l,r,1)<<endl;
            }
        }
    }
    return 0;
}

 

 
posted @ 2018-03-26 23:05  litos  阅读(262)  评论(0编辑  收藏  举报