P3688 [ZJOI2017]树状数组

先讲一句废话,因为有mod 2,所以这题的计算只有异或。

题解告诉我们,这个写错的树状数组的作用是单点修改,询问后缀异或和。

至于证明的话,作为一名蒟蒻,我选择打表冷静一下。

P3688 [ZJOI2017]树状数组_第1张图片

感性理解后,发现就是对的。然后,

P3688 [ZJOI2017]树状数组_第2张图片

题解又说了,这样就能轻易想到动态二维数点。(讲道理打死我都想不到)

将每个修改看成一个点(L,R),询问看成一个矩形x≤r,y≥r(l=1)或两个矩形x≤r,y≥r和x≤l-1,y≥l-1

(l>1)。其中,两个矩形有重叠让人很不爽,所以改成三个矩形x≤l,l≤y

然后发现还是不会。

听说有种好姿势叫cdq分治,核心是分治时要考虑前半段对后半段的影响。

这样讲了等于没讲,那就直接以这题为例。

对询问的顺序进行分治,先处理好前半段,再取出后半段所有询问和前半段所有修改,进行静态二维数点,结果由全局变量保存。

代码思路:

init:
pii pos[N];
struct REC{int o,L,R,D,U,w;}rec[N];
int wzp[N],wzr[N],lnp,lnr,ans[N];//wz表示最右能到达的位置 
if(x==1){
	pos[++lnp]= mkp(y,z);
}
else if(y==1){
	rec[++lnr]={1,z,z,n};
}
else{
	rec[++lnr]={i,1,z,y,z-1,1};
	rec[++lnr]={i,y+1,z,z,n,1}; 
	rec[++lnr]={i,1,y,z,n,2};
}
cdq(1,n);
int cdq(int le,int ri){
	if(le==ri){
		return;
	}
	int mid=le+ri>>1;
	cdq(le,mid),cdq(mid+1,r);
	solve(wzp[le],wzp[ri],wzr[le-1]+1,wzr[ri]);
}
struct VEC{
	int o,L,R;//表示点时o为0,表示矩形是为下标,正负表示该加还是减。 
}vec[N];int cnt;
bool operator <(VEC x,VEC y){
	if(x.L!=y.L)return x.L0)adda();
			else suba();
		}
	}
}

为什么add和sub没有写呢?

因为我发现写sub的时候p=(p'+q)/(1-2q),q=1/2时无意义!

所以该怎么办呢?蒟蒻想了很久也没能解决问题,最终选择向黑恶势力低头,改用二维线段树!

虽然二维线段树很烧内存,但我还是想赌一把,希望通过卡常把这题A掉。(讲道理现在不是在考场上,多爆几发OJ没有太大问题)


你可能感兴趣的:(luogu,*unsolved)