• Just Another Game of Stones 南京ICPC 吉司机线段树 + 尼姆博弈


    Just Another Game of Stones 吉司机线段树 + 尼姆博弈

    题目大意:

    给你n个数,有两种操作:

    • 给你 (l,r,x) 表示在区间 ([l,r]) 更新 (b[i] = max(b[i],x))
    • 给你 (l,r,x) 表示求区间 ([l,r]) 和 一堆数量为 (x) ,问先手有多少种不同的方案数使得在 (r - l +2) 堆石头的尼姆博弈中获得胜利。

    题解:

    对于第一种操作,很明显可以用吉斯机线段树解决,对于第二种操作,首先你要明白如何求尼姆博弈先手胜利的方案数,如果有 (m) 堆石头,假设 (sum)(n) 堆石头的异或和,那么对于第 (i) 堆石头,假设这堆有 (y) 个石头,那么如果 (y>sum \,\,xor\,\,y) 则先手胜利,如果对于 (sum) 的二进制的最高位,如果 (y) 这一个二进制位 (bit = 1) ,那么 (y>sum \,\,xor\,\,y) ,如果 (bit = 0) ,那么 (y<sum \,\,xor\,\,y) ,所以只需要维护二进制的状态即可。

    这个题目把我写的要吐血了,重构了好几回,写了两天,发现我的inf设置的小了。。。昨天晚上就可以A的,真的要把我给气死了。。。

    我令 (inf = 0x3f3f3f3f) 不够,应该设置成这个的两倍或者 (inf = INT\_MAX;)

    //最后重构的代码
    #include <bits/stdc++.h>
    #define lson (id<<1)
    #define rson (id<<1|1)
    using namespace std;
    const int maxn = 2e5 + 10;
    const int inf = INT_MAX;
    const int base = 31;
    int seg[maxn<<2],mi[maxn<<2],se[maxn<<2],cnt[maxn<<2],lazy[maxn<<2],bit[maxn<<2][33];
    int a[maxn];
    void pushUp(int id){
        seg[id] = seg[lson] ^ seg[rson];
        for(int i=0;i<base;i++) bit[id][i] = bit[lson][i] + bit[rson][i];
        if(mi[lson]==mi[rson]){
            mi[id] = mi[lson],cnt[id] = cnt[lson] + cnt[rson];
            se[id] = min(se[lson],se[rson]);
        }
        else{
            int ls = lson,rs = rson;
            if(mi[rs]<mi[ls]) swap(ls,rs);
            mi[id] = mi[ls],cnt[id] = cnt[ls];
            se[id] = min(se[ls],mi[rs]);
        }
    }
    void build(int id,int l,int r){
        lazy[id] = 0;
        if(l==r){
            seg[id] = mi[id] = a[l];
            se[id] = inf,cnt[id] = 1;
            for(int i=0;i<base;i++) bit[id][i] = (a[l]>>i&1);
            return ;
        }
        int mid = (l+r)>>1;
        build(lson,l,mid);
        build(rson,mid+1,r);
        pushUp(id);
    }
    void work(int id,int v){
        if(cnt[id]&1) seg[id]^=mi[id]^v;
        for(int i=0;i<base;i++) {
            bit[id][i] -= (mi[id]>>i&1)*cnt[id];
            bit[id][i] += (v>>i&1)*cnt[id];
        }
        mi[id] = lazy[id] = v;
    }
    void pushDown(int id){
        if(lazy[id]>mi[lson]) work(lson,lazy[id]);
        if(lazy[id]>mi[rson]) work(rson,lazy[id]);
    }
    void update(int id,int l,int r,int x,int y,int v){
        if(v<=mi[id]) return;
        if(x<=l&&y>=r&&v<se[id]){
            work(id,v);
            return ;
        }
        pushDown(id);
        int mid = (l+r)>>1;
        if(x<=mid) update(lson,l,mid,x,y,v);
        if(y>mid) update(rson,mid+1,r,x,y,v);
        pushUp(id);
    }
    int queryXor(int id,int l,int r,int x,int y){
        if(x<=l&&y>=r) return seg[id];
        int ans = 0,mid = (l+r)>>1;
        pushDown(id);
        if(x<=mid) ans^=queryXor(lson,l,mid,x,y);
        if(y>mid) ans^=queryXor(rson,mid+1,r,x,y);
        return ans;
    }
    int queryBit(int id,int l,int r,int x,int y,int p){
        if(x<=l&&y>=r) return bit[id][p];
        int ans = 0,mid = (l+r)>>1;
        pushDown(id);
        if(x<=mid) ans+=queryBit(lson,l,mid,x,y,p);
        if(y>mid) ans+=queryBit(rson,mid+1,r,x,y,p);
        return ans;
    }
    int main(){
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,1,n);
        while(q--){
            int op,l,r,x;
            scanf("%d%d%d%d",&op,&l,&r,&x);
            if(op==1) update(1,1,n,l,r,x);
            else{
                int sum = queryXor(1,1,n,l,r)^x,ans = (x>(sum^x));
                if(sum>0){
                    int now = sum,pos = -1;
                    while(now) now>>=1,pos++;
                    ans += queryBit(1,1,n,l,r,pos);
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    
    //之前优化的代码
    #include <bits/stdc++.h>
    #define lson (id<<1)
    #define rson (id<<1|1)
    using namespace std;
    const int maxn = 2e5+10;
    const int inf = INT_MAX;
    typedef long long ll;
    struct node{ // 维护二进制的线段树
        int mi,se,cnt,lazy,s,bit[40];
    }tree[maxn<<2];
    int a[maxn];
    void push_up(int id){
        tree[id].s = tree[lson].s ^ tree[rson].s;
        int ls = id<<1,rs = id<<1|1;
        if(tree[lson].mi == tree[rson].mi){
            tree[id].mi = tree[lson].mi;
            tree[id].cnt = tree[lson].cnt + tree[rson].cnt;
            tree[id].se = min(tree[lson].se,tree[rson].se);
        }
        else {
            if (tree[lson].mi < tree[rson].mi) swap(ls, rs);
            tree[id].mi = tree[rs].mi;
            tree[id].cnt = tree[rs].cnt;
            tree[id].se = min(tree[rs].se, tree[ls].mi);
        }
        for(int i=0;i<31;i++) tree[id].bit[i] = tree[lson].bit[i] + tree[rson].bit[i];
    }
    void build(int id,int l,int r){
        tree[id].lazy = -1;
        if(l==r){
            tree[id].mi = tree[id].s = a[l];
            tree[id].se = inf,tree[id].cnt = 1;
            for(int i=0;i<31;i++) tree[id].bit[i] = a[l]>>i&1;
            return ;
        }
        int mid = (l+r)>>1;
        build(lson,l,mid);
        build(rson,mid+1,r);
        push_up(id);
    }
    void work(int id,int val){
        if(tree[id].cnt&1) tree[id].s ^= tree[id].mi ^ val;
        for(int i=0; i<31; ++i){
            tree[id].bit[i] -= (tree[id].mi>>i&1)*tree[id].cnt;
            tree[id].bit[i] += (val>>i&1)*tree[id].cnt;
        }
        tree[id].lazy = tree[id].mi = val;
    }
    void push_down(int id){
        if(tree[id].lazy>tree[lson].mi) work(lson,tree[id].lazy);
        if(tree[id].lazy>tree[rson].mi) work(rson,tree[id].lazy);
    }
    
    void update(int id,int l,int r,int x,int y,int val){
        if(x>r||y<l||val<=tree[id].mi) return ;
        int mid = (l+r)>>1;
        if(x<=l&&y>=r&&tree[id].se>val){
            work(id,val);
            return ;
        }
        push_down(id);
        if(x<=mid) update(lson,l,mid,x,y,val);
        if(y>mid) update(rson,mid+1,r,x,y,val);
        push_up(id);
    }
    int queryXor(int id,int l,int r,int x,int y){
        if(x>r||y<l) return 0;
        if(x<=l&&y>=r) return tree[id].s;
        int mid = (l+r)>>1,ans = 0;
        push_down(id);
        if(x<=mid) ans ^= queryXor(lson,l,mid,x,y);
        if(y>mid) ans ^= queryXor(rson,mid+1,r,x,y);
        return ans;
    }
    int querySum(int id,int l,int r,int x,int y,int f){
        if(x>r||y<l) return 0;
        if(x<=l&&y>=r) return tree[id].bit[f];
        push_down(id);
        int mid = (l+r)>>1,ans = 0;
        if(x<=mid) ans+=querySum(lson,l,mid,x,y,f);
        if(y>mid) ans+=querySum(rson,mid+1,r,x,y,f);
        return ans;
    }
    
    int main(){
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,1,n);
        while(q--){
            int op,l,r,x;
            scanf("%d%d%d%d",&op,&l,&r,&x);
            if(op==1) update(1,1,n,l,r,x);
            else{
                int sum = queryXor(1,1,n,l,r)^x;
                int ans = 0;
                if(sum>0){
                    int now = sum,pos = -1;
                    while(now) now>>=1,pos++;
                    ans = querySum(1,1,n,l,r,pos);
                    if(x>(sum^x)) ans++;
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    
    //第一份AC代码
    #include <bits/stdc++.h>
    #define lson (id<<1)
    #define rson (id<<1|1)
    using namespace std;
    const int maxn = 2e5 + 10;
    const int inf = INT_MAX;
    const int base = 31;
    int seg[maxn<<2],mi[maxn<<2],se[maxn<<2],cnt[maxn<<2],lazy[maxn<<2],bit[maxn<<2][33];
    int a[maxn];
    void pushUp(int id){
        seg[id] = seg[lson] ^ seg[rson];
        for(int i=0;i<base;i++) bit[id][i] = bit[lson][i] + bit[rson][i];
        if(mi[lson]==mi[rson]){
            mi[id] = mi[lson],cnt[id] = cnt[lson] + cnt[rson];
            se[id] = min(se[lson],se[rson]);
        }
        else{
            int ls = lson,rs = rson;
            if(mi[rs]<mi[ls]) swap(ls,rs);
            mi[id] = mi[ls],cnt[id] = cnt[ls];
            se[id] = min(se[ls],mi[rs]);
        }
    }
    void build(int id,int l,int r){
        lazy[id] = 0;
        if(l==r){
            seg[id] = mi[id] = a[l];
            se[id] = inf,cnt[id] = 1;
            for(int i=0;i<base;i++) bit[id][i] = (a[l]>>i&1);
            return ;
        }
        int mid = (l+r)>>1;
        build(lson,l,mid);
        build(rson,mid+1,r);
        pushUp(id);
    }
    void work(int id,int v){
        if(cnt[id]&1) seg[id]^=mi[id]^v;
        for(int i=0;i<base;i++) {
            bit[id][i] -= (mi[id]>>i&1)*cnt[id];
            bit[id][i] += (v>>i&1)*cnt[id];
        }
        mi[id] = lazy[id] = v;
    }
    void pushDown(int id){
        if(lazy[id]>mi[lson]) work(lson,lazy[id]);
        if(lazy[id]>mi[rson]) work(rson,lazy[id]);
    }
    void update(int id,int l,int r,int x,int y,int v){
        if(v<=mi[id]) return;
        if(x<=l&&y>=r&&v<se[id]){
            work(id,v);
            return ;
        }
        pushDown(id);
        int mid = (l+r)>>1;
        if(x<=mid) update(lson,l,mid,x,y,v);
        if(y>mid) update(rson,mid+1,r,x,y,v);
        pushUp(id);
    }
    int queryXor(int id,int l,int r,int x,int y){
        if(x<=l&&y>=r) return seg[id];
        int ans = 0,mid = (l+r)>>1;
        pushDown(id);
        if(x<=mid) ans^=queryXor(lson,l,mid,x,y);
        if(y>mid) ans^=queryXor(rson,mid+1,r,x,y);
        return ans;
    }
    int queryBit(int id,int l,int r,int x,int y,int p){
        if(x<=l&&y>=r) return bit[id][p];
        int ans = 0,mid = (l+r)>>1;
        pushDown(id);
        if(x<=mid) ans+=queryBit(lson,l,mid,x,y,p);
        if(y>mid) ans+=queryBit(rson,mid+1,r,x,y,p);
        return ans;
    }
    int main(){
        int n,q;
        scanf("%d%d",&n,&q);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        build(1,1,n);
        while(q--){
            int op,l,r,x;
            scanf("%d%d%d%d",&op,&l,&r,&x);
            if(op==1) update(1,1,n,l,r,x);
            else{
                int sum = queryXor(1,1,n,l,r)^x,ans = (x>(sum^x));
                if(sum>0){
                    int now = sum,pos = -1;
                    while(now) now>>=1,pos++;
                    ans += queryBit(1,1,n,l,r,pos);
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    normalize.css介绍和使用,normalize与CSS Reset的区别
    解决在Windows10没有修改hosts文件权限
    定时器
    常见代码题
    BFC与margin重叠
    清除浮动的方法以及优缺点
    面向对象的理解
    左边固定右边自适应
    正则
    《STL源码剖析》——第一、二、三章
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/14372561.html
Copyright © 2020-2023  润新知