XOR的艺术

题目

https://www.luogu.org/problemnew/show/P2574

思路

首先,由于是区间修改和区间查询,并且数据范围还这么大,所以需要使用线段树来维护。 读入的数都是0或1且修改操作为异或1的话,那么lazytag和线段树的维护就很好想了。

因为01=1,11=0,所以本题如果对同一个区间连续异或1两次,得到的结果和没有异或是一样的。
对于线段树中不是叶子结点的节点,它的值是它的左右子树的和,也就是它对应的这段区间里面1的个数(因为只有0和1,所以它的值是几就有几个1)。

如果对于一段区间,长度为len,有n个1,那么就有len-n个0。相应地,对这段区间异或1之后,它的1的个数就变成了len-n。
这就是这个题的基本思路。还有一些需要注意的点:

读入的时候一定要按照字符读入,否则就直接读入了所有的数(因为没有空格)。

如果说区间长度并不能整除以2,那么就把除以二向下取整丢给左儿子,然后把剩下的丢给右儿子。

代码

#include
#include
#include
#include
using namespace std;
const int M=500500;
struct Tree
{
    int son[2],bond[2];
    int la,asum;
}t[M];
int n,m;
string s;
int num[M],cnt=1,rt=0;
void up(int x)
{
    int ls=t[x].son[0];
    int rs=t[x].son[1];
    t[x].asum=t[ls].asum+t[rs].asum;
    t[x].bond[0]=t[ls].bond[0];
    t[x].bond[1]=t[rs].bond[1];
    return ;
}
void built(int l,int r,int cur)
{
    if (l==r) 
    {
        t[cur].asum=num[l];
        t[cur].bond[0]=t[cur].bond[1]=l;
        t[cur].son[0]=t[cur].son[1]=-1;
        return ; 
    }
    t[cur].son[0]=cnt++;
    t[cur].son[1]=cnt++;
    int mid=(l+r)>>1;
    built(l,mid,t[cur].son[0]);
    built(mid+1,r,t[cur].son[1]);
    up(cur);
    return ;
}
void down(int x)
{
    if (t[x].la%2==0) return ;
    int ls=t[x].son[0];
    int rs=t[x].son[1];
    t[ls].asum=(t[ls].bond[1]-t[ls].bond[0]+1-t[ls].asum);
    t[rs].asum=(t[rs].bond[1]-t[rs].bond[0]+1-t[rs].asum);
    t[ls].la++;
    t[rs].la++;
    t[x].la=0;
    return ;
}
void date(int l,int r,int val,int cur)
{
    if (l<=t[cur].bond[0]&&t[cur].bond[1]<=r)
    {
        t[cur].asum=(t[cur].bond[1]-t[cur].bond[0]+1-t[cur].asum);
        t[cur].la++;
        return ;
    }
    down(cur);
    int mid=(t[cur].bond[0]+t[cur].bond[1])>>1;
    if (l<=mid) date(l,r,val,t[cur].son[0]);
    if (r>mid) date(l,r,val,t[cur].son[1]);
    up(cur);
    return ;
}
int query(int l,int r,int x)
{
    if (l<=t[x].bond[0]&&t[x].bond[1]<=r) return t[x].asum;
    down(x);up(x);int tot=0;
    int mid=(t[x].bond[0]+t[x].bond[1])>>1;
    if (l<=mid) tot+=query(l,r,t[x].son[0]);
    if (r>mid) tot+=query(l,r,t[x].son[1]);
    return tot; 
}
int main()
{
    scanf("%d %d",&n,&m);cin>>s;
    for (int i=1;i<=n;i++) num[i]=s[i-1]-'0';
    built(1,n,rt);
    while (m--)
    {
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        if (a==0)
        {
            date(b,c,1,rt);
        }
        else cout<

你可能感兴趣的:(题解)