zoukankan      html  css  js  c++  java
  • 线段树+二进制位拆分【CF242E】XOR on Segment

    Description

    给定一个长为(n(n<=10^5))的数组

    数组里的数不超过(10^6)

    有两种操作:

    1:求(sum[l,r]);

    2:对([l,r])中的所有数和(x)异或

    Input

    第一行一个整数(n),代表有一个长度为(n)的数组。

    第二行(n)个整数,代表(a_i)

    第三行为一个整数(m),代表有(m)次操作。

    接下来(m)行每行描述一个操作。

    Output

    对于每一个操作(1),输出一行代表(sum[l,r]).

    这题不错,线段树+二进制拆位

    由于异或不具有叠加性,所以不能用(lazy)标记直接异或。

    我们记录(tr[o][i])代表当前节点(o),二进制位(i)上是(1)的数有多少个。

    由于,如果某一二进制位上原来为(1),且当前异或的数(x),当前二进制位上也有(1),那么我们的当前(tr[o][i]=r-l+1-tr[o][i])

    可以理解为(01)交换。

    然后由于(2^{20})(10^6)要大。

    所以只需要拆到(20)即可。

    然后直接计算即可。

    PS:记得开(long long)

    代码

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #define int long long 
    #define R register
    
    using namespace std;
    
    const int gz=1e5+8;
    
    inline void in(R int &x)
    {
    	R int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    
    int n,tr[gz<<2][21],tg[gz<<2],m;
    
    #define ls o<<1
    #define rs o<<1|1
    
    inline void up(R int o)
    {
    	for(R int i=20;~i;i--)
    		tr[o][i]=tr[ls][i]+tr[rs][i];
    }
    
    void build(R int o,R int l,R int r)
    {
    	if(l==r)
    	{
    		R int x;in(x);
    		for(R int i=20;~i;i--)
    			if((x>>i)&1)tr[o][i]++;
    		return;
    	}
    	R int mid=(l+r)>>1;
    	build(ls,l,mid);
    	build(rs,mid+1,r);
    	up(o);
    }
    
    inline void down(R int o,R int l,R int r)
    {
    	if(tg[o]==0)return;
    	tg[ls]^=tg[o];tg[rs]^=tg[o];
    	R int mid=(l+r)>>1;
    	for(R int i=20;~i;i--)
    	{
    		if((tg[o]>>i)&1)
    			tr[ls][i]=mid-l+1-tr[ls][i],
    			tr[rs][i]=r-mid-tr[rs][i];
    	}
    	tg[o]=0;
    	return;
    }
    
    void change(R int o,R int l,R int r,R int x,R int y,R int k)
    {
    	if(x<=l and y>=r)
    	{
    		tg[o]^=k;
    		for(R int i=20;~i;i--)
    			if((k>>i)&1)
    				tr[o][i]=r-l+1-tr[o][i];
    		return;
    	}
    	down(o,l,r);
    	int mid=(l+r)>>1;
    	if(x<=mid)change(ls,l,mid,x,y,k);
    	if(y>mid) change(rs,mid+1,r,x,y,k);
    	up(o);
    }
    
    int query(R int o,R int l,R int r,R int x,R int y)
    {
    	if(x<=l and y>=r)
    	{
    		R int res=0;
    		for(R int i=20;~i;i--)
    			res+=(1<<i)*tr[o][i];
    		return res;
    	}
    	down(o,l,r);
    	R int mid=(l+r)>>1,as=0;
    	if(x<=mid)as+=query(ls,l,mid,x,y);
    	if(y>mid)as+=query(rs,mid+1,r,x,y);
    	return as;
    }
    
    signed main()
    {
    	in(n);build(1,1,n);in(m);
    	for(R int opt,l,r,x;m;m--)
    	{
    		in(opt);
    		if(opt==1)
    		{
    			in(l),in(r);
    			printf("%lld
    ",query(1,1,n,l,r));
    		}
    		else
    		{
    			in(l),in(r),in(x);
    			change(1,1,n,l,r,x);
    		}
    	}
    }
    
  • 相关阅读:
    封装成帧、帧定界、帧同步、透明传输(字符计数法、字符串的首尾填充法、零比特填充的首尾标志法、违规编码法)
    计算机网络之数据链路层的基本概念和功能概述
    物理层设备(中继器、集线器)
    计算机网络之传输介质(双绞线、同轴电缆、光纤、无线电缆、微波、激光、红外线)
    计算机网络之编码与调制
    0953. Verifying an Alien Dictionary (E)
    1704. Determine if String Halves Are Alike (E)
    1551. Minimum Operations to Make Array Equal (M)
    0775. Global and Local Inversions (M)
    0622. Design Circular Queue (M)
  • 原文地址:https://www.cnblogs.com/-guz/p/9924726.html
Copyright © 2011-2022 走看看