Nim Game(2021 JLCPC I)

Gym 103486I

题目大意

给你N堆石子,第i堆中石子的个数是Ai,现有M次操作,每次有两种操作:11 l r x表示从第l堆到第r堆,每堆石子的个数都加上x22 l r表示问你从第i堆到第r堆,能否从中挑出若干堆使得他们的异或和为0(1N105,1M105,1Ai109,1x104)

思路

首先肯定会想到建一棵能够支持区间修改并且查询异或和的线段树,但是显然是做不了的,但是我们又能发现,当堆数超过32的时候,一定能找到几堆使得他们的异或和为0,于是我们就可以建一棵能够支持区间修改并单点查询区间和的线段树就可以了,当堆数小于等于32的时候,我们可以单点查询并且用线性基来做,大于32了的话,就直接输出Yes好了,然后就能轻松AC了。

代码

#include<bits/stdc++.h>
using namespace std;
int a[100005];
int tree[100005<<2],laz[100005<<2];
void build(int p,int l,int r)
{
    laz[p]=0;
    if(l==r)
    {
        tree[p]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    tree[p]=tree[p<<1]+tree[p<<1|1];
}
void pushdown(int p,int l,int r)
{
    int mid=(l+r)>>1;
    tree[p<<1]+=laz[p]*(mid-l+1);
    tree[p<<1|1]+=laz[p]*(r-mid);
    laz[p<<1]+=laz[p];
    laz[p<<1|1]+=laz[p];
    laz[p]=0;
}
void update(int p,int l,int r,int w,int x,int y)
{
    if(x<=l&&r<=y)
    {
        tree[p]+=w*(r-l+1);
        laz[p]+=w;
        return;
    }
    pushdown(p,l,r);
    int mid=(l+r)>>1;
    if(x<=mid)update(p<<1,l,mid,w,x,y);
    if(mid<y)update(p<<1|1,mid+1,r,w,x,y);
    tree[p]=tree[p<<1]+tree[p<<1|1];
}
int query(int p,int l,int r,int x)
{
    if(l==r)return tree[p];
    pushdown(p,l,r);
    int mid=(l+r)>>1;
    if(x<=mid)return query(p<<1,l,mid,x);
    else return query(p<<1|1,mid+1,r,x);
}
int p[35];
bool insert(int x)
{
    for(int i=31;i>=0;i--)
    {
        if(x>>i)
        {
            if (p[i])
                x ^= p[i];
            else
            {
                p[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    build(1,1,n);
    while(m--)
    {
        int op,l,r,x;
        scanf("%d%d%d",&op,&l,&r);
        if(op==1)
        {
            scanf("%d",&x);
            update(1,1,n,x,l,r);
        }
        else
        {
            if(r-l+1>32)printf("Yes\n");
            else
            {
                for(int i=0;i<=31;i++)p[i]=0;
                bool can=0;
                for(int i=l;i<=r;i++)
                {
                    int num=query(1,1,n,i);
                    if(insert(num)==0)
                    {
                        can=1;
                        break;
                    }
                }
                if(can)printf("Yes\n");
                else printf("No\n");
            }
        }
    }
    return 0;
}

__EOF__

本文作者Jerry-Black
本文链接https://www.cnblogs.com/Jerry-Black/p/16104882.html
关于博主:小蒟蒻一只( ̄^ ̄)ゞ
版权声明:转载请注明来源哟~ QAQ
声援博主:UP UP UP !!!
posted @   Jerry_Black  阅读(68)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示