题意:
思路:
参考博客:https://www.cnblogs.com/MashiroSky/p/5973686.html
非常非常难写的线段树,不仅难想还难写。
首先,这个线段树维护的是什么,是该区域四个顶点的连通性
比如维护一个宽度为6的区域,我们维护的就是图中1,2,3,4的连通性。
然后考虑怎么合并两个区间,因为合并的时候,两个子区间都是已经内部联通好的了,因为我们并不在意具体路径,只要能联通就可以了,所以,合并区间就相当于这样:
其中1234为左儿子的区间,5678为右儿子的区间,我们发现想要合并两个区间,就需要知道25,47的连通性,也就是mid和mid+1的连通性。
事实上,最后我们维护了8个连通性,分别是1和2,1和3,1和4,2和3,3和4,2和4,mid和mid+1的第一行连通性,mid和mid+1的第二行连通性。
具体更新的时候,两个格子的相对位置是需要分类讨论的。而pushup的操作大家在理解连通性以后就很好理解了。
最后想想怎么查询,比如我们询问上图2,7的连通性,其中2可能需要先向左跑,然后再跑到7(上面贴的dalao的博客有更详细的解释),正是因为这种情况,我们就需要把区间切成3部分(就是三个区间),第一部分是1到c1,第二部分是c1到c2,第三部分是c2到n。这样就能处理掉上面说的跑法了。
错误及反思:
代码:
代码也参考了大佬的代码(其实最后都改得没啥区别了),说句实话,没这位dalao的代码我根本写不出来,太难写了
#include<bits/stdc++.h>
using namespace std;
const int N = 201000;
#define ls rt<<1
#define rs rt<<1|1
/*
U:第一行mid,mid+1两列之间是否联通
D:第二行mid,mid+1两列之间是否联通
l:s1,s3是否联通
r:s2,s4是否联通
u:s1,s2是否联通
d:s3,s4是否联通
q:s1,s4是否联通
p:s3,s2是否联通
*/
int n;
char s[10];
struct Segtree{
int U,D,l,r,u,d,q,p;
}seg[N<<2];
void pushup(Segtree &rt,Segtree l,Segtree r){
rt.l=l.l||(l.u&&rt.U&&r.l&&rt