题解 CF587E 【Duff as a Queen】

题目链接

本题类似于[Ynoi2013]无力回天NOI2017

Solution CF587E Duff as a Queen

题目大意:维护一个序列,支持区间异或一个值,询问一段区间内有多少种任意子集的异或值

线段树,线性基


分析:

想这个题的时候有一个假了的地方:线性基是离线数据结构,没办法快速实现区间修改。把线性基里面所有数拖出来异或一遍再插回去,这个做法是假的

类似于用 (gcd(x,y)=gcd(y,x-y)) 这个性质做差分,变区间修改为单点修改从而实现区间加区间 (gcd),我们尝试对原序列进行等价转化,使得修改操作可以快速进行

假设原序列为 (a),那么我们令 (b_i=a_i;xor;a_{i+1}),对于原序列 (a_iquad i in[l,r]),我们可以用 (b_i quad iin(l,r]) 以及 (a_l) 来表示

这样我们只需要维护单点修改,区间查询线性基的并。以及维护区间异或,单点查询原序列

可以用树状数组和线段树来维护

#include <cstdio>
#include <cctype>
#include <cstring>
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
using namespace std;
const int maxn = 2e5 + 100;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
struct Base{
    static const int mx = 31;
    int p[mx + 1];
    inline void ins(int x){
        for(int i = mx;i >= 0;i--){
            if(!((x >> i) & 1))continue;
            if(!p[i]){
                p[i] = x;
                break;
            }
            x ^= p[i];
        }
    }
    inline void ins(const Base &rhs){
        for(int i = 0;i <= mx;i++)
            ins(rhs.p[i]);
    }
    inline int query()const{
        int res = 0;
        for(int i = 0;i <= mx;i++)
            if(p[i])res++;
        return (1ll << res);
    }
    inline void clear(){memset(p,0,sizeof(p));}
};
int org[maxn],val[maxn],n,q;
namespace st{
	#define ls (rt << 1)
	#define rs (rt << 1 | 1)
	struct node{
		int real;
		Base val;
	}tr[maxn << 2];
	inline void pushup(int rt){
		tr[rt].val = tr[ls].val;
		tr[rt].val.ins(tr[rs].val);
	}
	inline void build(int l = 0,int r = n,int rt = 1){
		if(l == r){
			tr[rt].real = val[l];
			tr[rt].val.ins(val[l]);
			return;
		}
		int mid = (l + r) >> 1;
		build(l,mid,ls);
		build(mid + 1,r,rs);
		pushup(rt);
	}
	Base res;
	inline void query(int a,int b,int l = 0,int r = n,int rt = 1){
		if(a <= l && b >= r){
			res.ins(tr[rt].val);
			return;
		}
		int mid = (l + r) >> 1;
		if(a <= mid)query(a,b,l,mid,ls);
		if(b >= mid + 1)query(a,b,mid + 1,r,rs);
	}
	inline void modify(int pos,int v,int l = 0,int r = n,int rt = 1){
		if(l == r){
			tr[rt].real ^= v;
			tr[rt].val.clear();
			tr[rt].val.ins(tr[rt].real);
			return;
		}
		int mid = (l + r) >> 1;
		if(pos <= mid)modify(pos,v,l,mid,ls);
		else modify(pos,v,mid + 1,r,rs);
		pushup(rt);
	}
}
namespace bit{
	int f[maxn];
	inline int lowbit(int x){return x & (-x);}
	inline int query(int pos){
		int res = 0;
		while(pos){
			res ^= f[pos];
			pos -= lowbit(pos);
		}
		return res;
	}
	inline void modify(int pos,int v){
		if(!pos)return;
		while(pos < maxn){
			f[pos] ^= v;
			pos += lowbit(pos);
		}
	}
	inline void modify(int l,int r,int v){
		modify(l,v);
		modify(r + 1,v);
	}
}
int main(){
	n = read(),q = read();
	for(int i = 1;i <= n;i++)org[i] = read();
	for(int i = 1;i <= n;i++)bit::modify(i,i,org[i]);
	for(int i = 1;i <= n;i++)val[i] = org[i] ^ org[i + 1];
	st::build();
	while(q--){
		const int opt = read(),x = read(),y = read();
		if(opt == 1){
			const int k = read();
			st::modify(x - 1,k);
			st::modify(y,k);
			bit::modify(x,y,k);
		}else{
			st::res.clear();
			if(x != y)st::query(x,y - 1);
			st::res.ins(bit::query(x));
			printf("%d
",st::res.query());
		}
	}
}
原文地址:https://www.cnblogs.com/colazcy/p/13961449.html