zoukankan      html  css  js  c++  java
  • 【洛谷5607】[Ynoi2013] 无力回天NOI2017(线段树套线性基)

    点此看题面

    大致题意: 给定一个序列,要求支持两种操作:区间修改,异或一个数;求在一段区间中选任意个数与询问值(v)异或得到的最大值。

    前言

    本来想学一学(KD-Tree),结果不知道为什么(T)得很惨很惨,调了很久都没能调出来。

    心态爆炸,于是默默点开了Ynoi。。。

    看看,这Ynoi多良心,三个(log)堆在这里,而且连读优输优都没写,结果都(T)不掉。

    不过就是个线段树套线性基嘛,比(KD-Tree)好写多了,甚至还不用写什么噼(pia)里(pia)啪(pia)啦(pia)的重构。

    无力回天,如此弱小的我,恐怕是真的无力回天了啊!

    有那么一刻,我回想起了去年(CSP)的绝望,那连盘都摸不到的可怕。尽管现在看来去年CSP没有任何用处。

    有那么一刻,我回想起了曾经的一场场模拟赛,毫无悬念地被吊锤。纵使日薄西山,即便看不到未来,此时此刻的我,依旧是那么弱。

    有那么一刻,我回想起了那道名叫希望的题目,容斥+长链剖分+回退数据结构+离线求逆元,四倍役满,四倍退役。那就是希望,即便需要取模,也是光明。

    有那么一刻,我回想起了猪国杀,被大模拟所支配的日日夜夜,徘徊于冗长代码间的一天又一天。

    有那么一刻,我回想起了(AT678)尽管我没做过。因为此题是道非常残忍的题,可以的话我认为你应该先开心地做其他题,如果其他题做完了还有时间的话,就以此题为消遣吧。

    有那么一刻,我回想起了。。。

    怎么突然有种退役既视感,感觉自己像在写退役后的OI生涯总结。。。

    实际上只是听着窗外放的歌,看着这道题目的名称,心情突然激动起来了。。。

    咳咳,好,现在我们回到正题。

    线性基

    看看这道题的询问,你想到了什么?

    显然是线性基的经典操作嘛!

    这其实也就启示了我们,只要想办法维护出一段区间的线性基,我们就能轻松地实现询问了。

    可是,维护一段区间的线性基,又谈何容易?

    让我们来看看题面,区间修改?带修线性基?线性基还能这么玩?

    于是一脸懵逼的我开始了满脑子懵逼的思考,最后懵逼地无力回天。事实上,直至懵逼地点开题解前懵逼的那一刻,懵逼的我都始终保持着无比懵逼的状态。咳咳,又扯远了。

    线段树套线性基

    考虑是要维护一段区间的线性基,而我们知道,线性基的合并是可以在(O(log^2V))的复杂度内实现的。

    而且,修改一般的线性基是非常困难的,但如果修改只有一个元素的线性基呢?

    好了,话都说到这里了,不难明白,我所说的,正是线段树套线性基。

    这样的复杂度是(O(NlogNlog^2V))的。((CJJ)(log)(T)的哒?)

    等等,这样子似乎还是不能实现区间修改啊?

    因此,我们需要把区间修改转化为单点修改。

    怎么转化呢?这就需要利用异或这种神奇运算的神奇性质了。

    我们令(s_i=a_i xor a_{i-1}),然后我们发现,对于(i=l+1,l+2,...,r)(s_i)都不改变。而发生变化的仅仅是(s_l)(s_{r+1})两个值而已,这样一来就把区间修改转化为了单点修改。

    再等等,这么一搞之后,还怎么处理询问呢?

    然后我们发现,({a_l,a_{l+1},...,a_r})({a_l,s_{l+1},s_{l+2},...,s_r})二者的线性基是等价的。

    为什么?因为(s_i=a_i xor a_{i-1}),所以后者其实还是({a_l,a_{l+1},...,a_r})这堆东西在异或来异或去,并没有少掉谁,也没有多冒出来谁。

    所以,我们用线段树维护每个区间内(s_i)的线性基,询问时求出({s_{l+1},s_{l+2},...,s_r})的线性基,然后往里面扔入一个(a_l),我们就可以愉快地询问了。

    最后一次等等,这样不是还要维护(a_l)吗?

    是的,不过如果我们维护(s_i),然后就会发现(xor_{i=1}^ls_i=(xor_{i=1}^la_i) xor (xor_{i=1}^{l-1}a_i)=a_l)

    也就是说,只要实现单点修改以及求前缀和就可以了,树状数组显然可以很优秀地完成这项任务。

    写到这里,突然感觉维护线性基的线段树也可以直接借来做这个东西,反正都已经维护s了?算了,管它呢,反正写都写了,过都过了,还有啥好改的。

    具体实现详见代码。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 50000
    #define LV 30
    using namespace std;
    int n,a[N+5];
    class LinearBasis//线性基
    {
    	private:
    		#define LB LinearBasis
    		int v[LV+5];
    	public:
    		I LB() {for(RI i=LV;~i;--i) v[i]=0;}
    		I void Ins(RI x) {for(RI i=LV;~i;--i) if((x>>i)&1) {if(!v[i]) return (void)(v[i]=x);x^=v[i];}}//插入
    		I int Qry(RI x) {for(RI i=LV;~i;--i) (x^v[i])>x&&(x^=v[i]);return x;}//查询
    		I friend LB operator + (LB x,LB y) {for(RI i=LV;~i;--i) y.v[i]&&(x.Ins(y.v[i]),0);return x;}//合并
    };
    class SegmentTree//线段树
    {
    	private:
    		#define PT CI l=1,CI r=n,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1 
    		#define PU(x) (S[x]=S[x<<1]+S[x<<1|1])
    		int V[N<<2];LB S[N<<2];
    	public:
    		I void Build(int *a,PT)//建树
    		{
    			if(l==r) return S[rt].Ins(V[rt]=a[l]^a[l-1]);int mid=l+r>>1;
    			Build(a,LT),Build(a,RT),PU(rt);
    		}
    		I void U(CI x,CI v,PT)//单点修改
    		{
    			if(l==r) return (S[rt]=LB()).Ins(V[rt]^=v);int mid=l+r>>1;
    			x<=mid?U(x,v,LT):U(x,v,RT),PU(rt);
    		}
    		I LB Q(CI x,CI y,PT)//求出一段区间的线性基
    		{
    			if(x<=l&&r<=y) return S[rt];int mid=l+r>>1;
    			if(y<=mid) return Q(x,y,LT);if(x>mid) return Q(x,y,RT);
    			return Q(x,mid,LT)+Q(mid+1,y,RT);
    		}
    }S;
    class TreeArray//树状数组
    {
    	private:
    		int a[N+5];
    	public:
    		I void U(RI x,CI v) {W(x<=n) a[x]^=v,x+=x&-x;}//单点修改
    		I int Q(RI x,RI t=0) {W(x) t^=a[x],x-=x&-x;return t;}//求前缀和
    }T;
    int main()
    {
    	RI Qt,i,op,x,y,v;scanf("%d%d",&n,&Qt);
    	for(i=1;i<=n;++i) scanf("%d",a+i),T.U(i,a[i]^a[i-1]);
    	LB t;S.Build(a);W(Qt--) switch(scanf("%d%d%d%d",&op,&x,&y,&v),op)
    	{
    		case 1:S.U(x,v),T.U(x,v),y^n&&(S.U(y+1,v),T.U(y+1,v),0);break;//修改
    		case 2:(t=x^y?S.Q(x+1,y):LB()).Ins(T.Q(x)),printf("%d
    ",t.Qry(v));break;//询问
    	}return 0;
    }
    
  • 相关阅读:
    起床困难综合症[NOI2014]
    暗之链锁
    平凡的测试数据
    烤鸡翅
    高一寒假集训总结
    聪聪和可可[NOI2005]
    方伯伯的玉米田[SCOI2014]
    aix5下安装python和cx_Oracle
    同样的一句SQL语句在pl/sql 代码块中count 没有数据,但是直接用SQl 执行却可以count 得到结果
    关于SQL优化的一个小试例子
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5607.html
Copyright © 2011-2022 走看看