雅礼联考10-27 c 线段树

题意

  • 给你一个序列,\(q\)次询问一个区间内有多少个子区间满足自区间内所有的数进行按位与运算的结果是完全平方数

又是\(Lstete\)给我讲的...

他不久前给我讲的东西我又不会了我是真的捞

这种求区间内的子区间的题目

一般为了避免算重,可以考虑把询问离线挂在右端点上

我们首先可以发现一个性质

一个数进行按位与运算后结果一定不会变大

意思就是对于一个数不停进行与运算,只有\(log\)种取值

我们考虑一个数作为右端点的区间

这些区间进行按位与运算的取值只有\(log\)

并且取值相同的区间都是连续的

那么我们对于取值相同的区间可以一并修改

扫描二维码关注公众号,回复: 3755458 查看本文章

那么只要预处理出以每个数结尾二进制位为\(1\)的位中

离它最近的并且那一位为\(0\)的数的位置

就可以找到这些区间的断点了

这样做的复杂度是\(O(qlognlog1e9)\)

所以这题需要卡常.....

Codes

#include<bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;
const int M = 30 + 1;

unordered_map<int, bool> is;
vector<pair<int, int>> Q[N];

long long ans[N << 1];

int a[N], pre[M][N];

struct Segment_Tree 
{
#define mid ((l + r) >> 1)
#define ls (bh << 1)
#define rs (ls | 1)
#define lson ls, l, mid
#define rson rs, mid + 1, r

    long long S[N << 2], lazy[N << 2];

    void modify(int bh, int l, int r, long long val) 
    {
        lazy[bh] += val;
        S[bh] += (r - l + 1) * val;
    }

    void pushup(int bh) 
    {
        S[bh] = S[ls] + S[rs];
    }

    void pushdown(int bh, int l, int r) 
    {
        if(lazy[bh])
        {
            modify(lson, lazy[bh]);
            modify(rson, lazy[bh]);
            lazy[bh] = 0;
        }
    }

    void build(int bh, int l, int r) 
    {
        S[bh] = lazy[bh] = 0;
        if(l ^ r) build(lson), build(rson);
    }

    void update(int bh, int l, int r, int x, int y, long long z) 
    {
        if(x <= l && r <= y) 
            modify(bh, l, r, z);
        else 
        {
            pushdown(bh, l, r);
            if(x <= mid) update(lson, x, y, z);
            if(y > mid) update(rson, x, y, z);
            pushup(bh);
        }
    }

    long long query(int bh, int l, int r, int x, int y) 
    {
        long long res = 0;
        if(x <= l && r <= y) 
            res += S[bh];
        else 
        {
            pushdown(bh, l, r);
            if(x <= mid) res += query(lson, x, y);
            if(y > mid) res += query(rson, x, y);
        }
        return res;
    }

}T;

int main()
{
    //freopen("c.in", "r", stdin);
    //freopen("c.out", "w", stdout);

    int t, n, q, x, y;

    for(long long i = 0; i * i <= INT_MAX; ++ i)
        is[i * i] = true;

    for(scanf("%d", &t); t -- ; ) 
    {
        scanf("%d%d", &n, &q);
        for(int i = 1; i <= n; ++ i)
            scanf("%d", &a[i]);
        for(int i = 1; i <= q; ++ i)
        {
            scanf("%d%d", &x, &y);
            Q[y].push_back(make_pair(i, x));
        }

        T.build(1, 1, n);

        for(int i = 1; i < n; ++ i)
            for(int j = 0; j < M; ++ j)
            {
                if(a[i] >> j & 1)
                    pre[j][i + 1] = pre[j][i];
                else
                    pre[j][i + 1] = i;
            }

        for(int r = 1; r <= n; ++ r) 
        {
            int val = a[r], pos = r;
            while(pos) 
            {
                int last = 0;
                for(int j = 0; j < M; ++ j)
                    if(val >> j & 1)
                        last = max(last, pre[j][pos]);
                if(is[val])
                    T.update(1, 1, n, last + 1, pos, 1);
                pos = last, val &= a[last];
            }
            for(; !Q[r].empty(); Q[r].pop_back())
            {
                pair<int, int> now = Q[r].back();
                ans[now.first] = T.query(1, 1, n, now.second, r);
            }
        }
        memset(pre, 0, sizeof(pre));
        for(int i = 1; i <= q; ++ i)
            printf("%lld\n", ans[i]);
    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/brunch/p/9863677.html
今日推荐