hdu4737A Bit Fun 线段树

//给一串序列,问有多少对[i,j]使得
//[i,j]区间的所有数的或的值小于m
//可以知道'或'操作的加(a|b)>=max(a,b)
//可以枚举区间的右边r,找左边第一个不满足的位置
//然后在它们中间的r为由边界的区间都没满足
//对于找第一个不满足的位置,可以用线段树做,
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std ;
const int maxn = 100010 ;
#define left v << 1
#define right v<<1|1
struct node
{
    int l , r ;
    int value ;
}tree[maxn<<2] ;
int h[maxn] ;
int m ,n;
void build(int l , int r , int v)
{
    tree[v].l = l ;
    tree[v].r = r ;
    if(l == r)
    {
        tree[v].value = h[l] ;
        return  ;
    }
    int mid = (l + r) >> 1 ;
    build(l , mid , left) ;
    build(mid + 1 , r , right) ;
    tree[v].value = tree[left].value|tree[right].value ;
}
int get_ans(int v , int sum)
{
    if(tree[v].l == tree[v].r)
    return tree[v].l ;
    int mid = (tree[v].l + tree[v].r) >> 1 ;
    if((sum|tree[right].value) >= m)
    return get_ans(right , sum) ;
    else return get_ans(left , sum|tree[right].value) ;
}
int ans = 0 ;
int query(int v , int pos)
{
    if(tree[v].l == tree[v].r)
    return tree[v].value ;
    int mid = (tree[v].l + tree[v].r) >> 1 ;
    int sum ;
    if(pos <= mid)
    query(left , pos) ;
    else
    {
        sum = query(right , pos) ;
        if(sum < m && (sum|tree[left].value) >= m)
        {ans = get_ans(left , sum) ;}
        return sum|tree[left].value;
    }
}
int main()
{
    //freopen("in.txt" ,"r" ,stdin) ;
    int T ;
    scanf("%d" ,&T) ;
    int cas = 0 ;
    while(T--)
    {
        scanf("%d%d" ,&n , &m) ;
        for(int i = 1;i <= n;i++)
        scanf("%d" ,&h[i]) ;
        build(1 , n , 1) ;
        int sum = 0;
        for(int i = 1;i <= n ;i++)
        {
            ans = 0 ;
            if(h[i] >= m)
            {continue;}
            query(1 , i) ;
            sum += (i - ans);
        }
        query(1 , 9) ;
        printf("Case #%d: " ,++cas) ;
        printf("%d\n" ,sum) ;
    }
}


你可能感兴趣的:(线段树)