先讲一句废话,因为有mod 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没有太大问题)