Luogu P5607 [Ynoi2013]无力回天NOI2017

白给的一眼题。话说ynoi的题目名竟然与ACG无关了爷青结

题目的操作显然是让你用线性基维护,众所周知线性基是可以合并的,复杂度是\(O(\log^2 a_i)\)

所以容易想出用线段树来维护线性基,复杂度\(O(n\log n\log^2 a_i)\)和符合复杂度的样子

但是这里是区间修改啊,总不能一次重构一堆线性基吧

考虑利用异或的性质,我们小小地差分一下,令\(b_i=a_{i-1}\operatorname{xor} a_i\),那么区间修改的时候只需要修改\(b_l,b_{r+1}\)

那么问题来了,询问的时候我的线性基里就不是我想要的\(\{a_l,a_{l+1},\cdots,a_r\}\),那怎么搞?

考虑我们搞出\(\{a_l,b_{l+1},b_{l+2},\cdots,b_r\}\)\(\{a_l,a_l\operatorname{xor} a_{l+1},a_{l+1}\operatorname{xor} a_{l+2}\cdots,a_{r-1}\operatorname{xor} a_r\}\)

由于线性运算和线性基的定义我们发现在这个集合中随便异或来异或去和原来的\(\{a_l,a_{l+1},\cdots,a_r\}\)等效

然后就做完了,\(a_i=\operatorname{Xor}_{j=1}^i b_j\),线段树上顺带维护下即可,总体复杂度\(O(n\log n\log^2 a_i)\)

精准地写完一发入魂

#include
#include
#define RI register int
#define CI const int&
using namespace std;
const int N=50005,P=30;
int n,m,a[N],b[N],opt,x,y,z;
struct LB
{
	int v[P];
	inline LB() { memset(v,0,sizeof(v)); }
	inline void clear(void) { memset(v,0,sizeof(v)); }
	inline void insert(int x)
	{
		for (RI i=P-1;~i;--i) if ((x>>i)&1)
		{
			if (!v[i]) return (void)(v[i]=x); x^=v[i];
		}
	}
	inline int query(int x)
	{
		for (RI i=P-1;~i;--i) if ((x^v[i])>x) x^=v[i]; return x;
	}
	friend inline LB operator + (const LB& A,const LB& B)
	{
		LB C; RI i; for (i=0;i>1; build(LS); build(RS); pushup(now);
		}
		inline void updata(CI pos,CI val,TN)
		{
			if (pos>n) return; if (l==r) return S(now)=val,L(now).clear(),L(now).insert(val);
			int mid=l+r>>1; if (pos<=mid) updata(pos,val,LS); else updata(pos,val,RS); pushup(now);
		}
		inline LB query(CI beg,CI end,TN)
		{
			if (beg>end) return LB(); if (beg<=l&&r<=end) return L(now); LB ret; int mid=l+r>>1;
			if (beg<=mid) ret=ret+query(beg,end,LS); if (end>mid) ret=ret+query(beg,end,RS); return ret;
		}
		inline int presum(CI beg,CI end,TN)
		{
			if (beg<=l&&r<=end) return S(now); int mid=l+r>>1,ret=presum(beg,end,LS);
			if (end>mid) ret^=presum(beg,end,RS); return ret;
		}
		#undef S
		#undef L
		#undef TN
		#undef LS
		#undef RS
}SEG;
int main()
{
	RI i; for (scanf("%d%d",&n,&m),i=1;i<=n;++i) 
	scanf("%d",&a[i]),b[i]=a[i-1]^a[i]; for (SEG.build(),i=1;i<=m;++i)
	{
		scanf("%d%d%d%d",&opt,&x,&y,&z);
		if (opt==1) SEG.updata(x,b[x]^=z),SEG.updata(y+1,b[y+1]^=z);
		else t=SEG.query(x+1,y),t.insert(SEG.presum(1,x)),printf("%d\n",t.query(z));
	}
	return 0;
}

你可能感兴趣的:(Luogu P5607 [Ynoi2013]无力回天NOI2017)