• UVALive 8518


    UVALive 8518 - Sum of xor sum


    做法:线段树维护:答案,边界在左端点的区间异或为1的个数,边界在右端点异或为1的个数,1的个数,区间长度,这样已经自洽了。(每次讲线段树,都会讲这个题,比较经典的思想)

    ----update:2018/10/09
    首先,我们考虑拆位,分别计算每一位的贡献然后合并出答案,现在序列的元素只包含0或1。我们希望用线段树维护,异或为1的区间的个数,即包含奇数个1的区间的个数。那么,假设现在已知,[L,mid]有多少个区间包含奇数个1,[mid+1,R]有多少个区间包含奇数个1,那么合并后的区间的答案,就是左边的答案+右边的答案+横跨两个区间的答案。

    横跨两个区间的答案 = (左边以mid为右端点包含奇数个1的区间的数目) * (右边以(mid+1)为左端点包含偶数个1的区间的数目) + (左边以mid为右端点包含偶数个1的区间的数目) * (右边以(mid+1)为左端点包含奇数个1的区间的数目)

    那么现在就需要我们维护上边这4个东西,显然如果知道奇数的贡献,就很容易可以计算出偶数贡献。所以实际只用维护2个东西。这两个东西也可以用类似的思想维护出来,所以我们不用维护其他的东西了。引用大佬的话:“这类题目就是需要什么维护什么,直到数据结构自洽”当然,如果发现需要维护的东西过多,就要考虑换个思路了。

    #include <bits/stdc++.h>
    #define pb push_back
    typedef long long ll;
    const int N = 1e5 + 7;
    const int inf = 0x3f3f3f3f3f;
    const int mod = 1e9 + 7;
    using namespace std;
    int T, n, q, a[N];
    struct node{
        ll ans[20], lx[20], rx[20];
        int num[20], len;
    } tree[N<<2];
    node mer(node &a,node &b) {
        node res;
        for(int i = 0; i < 20; ++i) {
            res.ans[i] = a.ans[i] + b.ans[i];
            res.ans[i] += a.lx[i]*(b.len - b.rx[i]);
            res.ans[i] += (a.len - a.lx[i])*b.rx[i];
            if(b.num[i] & 1) res.lx[i] = b.lx[i] + (a.len - a.lx[i]);
            else res.lx[i] = b.lx[i] + a.lx[i];
            if(a.num[i] & 1) res.rx[i] = a.rx[i] + (b.len - b.rx[i]);
            else res.rx[i] = a.rx[i] + b.rx[i];
            res.num[i] = a.num[i] + b.num[i];
        }
        res.len = a.len + b.len;
        return res;
    }
    void build(int p, int l, int r) {
        if(l == r) {
            tree[p].len = 1;
            for(int i = 0; i < 20; ++i)
                if( a[l] & (1<<i) ) tree[p].ans[i] = tree[p].lx[i] = tree[p].rx[i] = tree[p].num[i] = 1;
                else tree[p].ans[i] = tree[p].lx[i] = tree[p].rx[i] = tree[p].num[i] = 0;
            return;
        }
        int mid = (l + r) >> 1;
        build(p<<1, l, mid); build(p<<1|1, mid+1, r);
        tree[p] = mer(tree[p<<1],tree[p<<1|1]);
    }
    node ask(int p,int l,int r,int L,int R) {
        if(l == L && R == r) {
            return tree[p];
        }
        int mid = (l + r) >> 1;
        if(R <= mid) return ask(p<<1,l,mid,L,R);
        else if(L > mid) return ask(p<<1|1,mid+1,r,L,R);
        else {
            node tmp1 = ask(p<<1,l,mid,L,mid);
            node tmp2 = ask(p<<1|1,mid+1,r,mid+1,R);
            return mer(tmp1,tmp2);
        }
    }
    int main() {
        scanf("%d", &T);
        while( T-- ) {
            scanf("%d%d",&n,&q);
            for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
            build(1,1,n);
            while(q--) { int l, r;
                scanf("%d %d",&l,&r);
                node tmp = ask(1,1,n,l,r);
                ll ans = 0;
                for(int i = 19; i >= 0; --i) 
                    ans = ((ans<<1LL)%mod + tmp.ans[i])%mod;
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
    
    
  • 相关阅读:
    典型页面布局
    网站表单输入框去除浏览器默认样式
    时间格式问题
    经典算法
    css自动换行
    git pull报“unable to update local ref”解决方案
    MYSQL数据插入和更新的语法
    正则表达式去除连续重复的字符
    linux保存住github的账号和密码
    php动态获取常量
  • 原文地址:https://www.cnblogs.com/RRRR-wys/p/9749591.html
Copyright © 2020-2023  润新知