collapse 题解:
题目事实上让我们数连通块个数。
一条边存在的时间肯定是一个区间。
我们询问把连接(<p,geq p)的点的边删除后的结果,这可以被转化为询问一个前缀的点的导出子图的连通块数,加上后缀的点的导出子图构成的连通块数。
后缀翻转后就是前缀,所以事实上我们需要询问一个前缀([1,p])的点的导出子图的连通块数。
如果没有删边,则问题可以转化为:
考虑被插入时间(t)小于等于现在时间(t1)的所有边对(x,y,x<y),数把(yleq p)的边插入后的连通块数。
这事实上是二维偏序,是经典的HNOI2016最小公倍数问题,可以分块解决。
但是我们维护的外部并查集只能算出([1,n])的连通块数。
注意到(>p)的点都是孤立点,所以我们把答案减去(n-p)即可得到前缀的导出子图的连通块数。
接下来考虑有删边的情况。
假设现在扫描到时间维块(b),把边分成(4)类。
第一类是在(b)内所有时间都存在的边,首先插入。
第二类是插入时间/删除时间在这个块的边,显然这种边只会有(sqrt{n})个。
第三类是在(b)内所有时间都不存在的边,不用管。
显然在扫到块(b)时可以给每条边分类。
考虑现在询问前缀([1,p])和时间(leq t1)的边,我们扫描第二类边集合。
如果在当前时间(t1)现在扫到的边存在,则插入并查集,且更新连通块数。
询问完后再全部撤销。
在接下来扫到块(b+1)时,把并查集复原成所有点都是孤立点后,再插入下一个块的第一类边。
时间复杂度(O((n+q)sqrt{n}log_2n))
难度:中
cat and dog题解:
随便拿一个节点出来作为根。
转化问题。
考虑原树被删的边划分成的连通块。
则每个连通块内最多只能有一个颜色的点。
如果一个连通块存在某种颜色的点,则把它染成这种颜色。
用dp解决这个问题,设(f_{i,0/1/2})表示当前(i)点所在的连通块是无色/白色/黑色,只考虑(i)和子树的点的最小代价。
转移枚举当前点的颜色和当前点的每个儿子。
如果儿子的颜色和当前相同,则不用删除当前点和儿子的边,否则需要。
现在考虑多组询问,考虑树剖+线段树维护。
一个节点的颜色变化显然只会影响到所有祖先的dp值。
考虑从被修改的节点(x)向上跳父亲。
对于每个节点,维护所有轻儿子的dp值更新当前节点。
(未完待续)
难度:易
Chef and Churu题解:
注意到单点修改,区间查询是个经典问题,可以用bit/分块解决。
考虑对函数序列分块,查询时边角直接用bit解决。
整块考虑维护整块的答案,然后(O(1))累加。
在修改时要更新每一块的答案,设原来是(y),修改后是(z),那么每块的答案要加上(z-y)乘以当前块所有区间覆盖当前修改位置的次数。
求出当前块的所有区间覆盖某个位置的次数很简单。
设(f_{i,j})表示第(i)块(j)位置被覆盖的次数,显然可以差分求出(f)。
然而用bit时间复杂度带(log_2),所以用分块解决。
难度:易
时代的眼泪
自己的做法有点奇怪,参考了区间逆序对的做法。
设一个询问的矩形为((p1,p2),(p3,p4))
定义(g(i,j))为顶部为(i),右部为(j),左/底部贴着平面的最左/最下边的答案
由于问题比区间逆序对强,所以考虑分块。
在分块时,序列被分为了(L,M,R)三个部分,(L,R)是左,右散块,(M)是中间整块。
每个点的贡献是以它为左下角的矩形和询问矩形的交。
(L,R)的贡献可以枚举(L)的每个节点,这样子贡献就是(R)平面上的一个子平面。
把每个块内的(a)离散化后显然可以二维前缀和。
为了避免二分,每个块(i)需要维护(f_{i,j})表示第(i)个块内小于(j)的最大数的排名。
(L,M)和(M,R)的贡献是对称的,所以只需要处理(L,M)的贡献。
二维前缀和后,转化成了计算顶部任意,右部贴着某个块,左/底部贴着平面的最左/最下边的答案。
设(s_{i,j})表示右部为第(i)个块的右端点,顶部为(j)的答案,显然可以把前(i)个块内的点排序后求。
(M)内部的每个节点的贡献可以被拆成在块内,块外的。
块内的贡献事实上就是求块内的纵坐标在查询下界,上界的点的逆序对个数。
一个块内最多只有(sqrt{n}*sqrt{n}=n)类贡献,可以通过前面的二维前缀和,枚举左端点,右端点递增处理。
找下界,上界在这个块内对应的贡献类型可以用前面提到的(f)。
设当前最右的整块的右部横坐标为(p)
设当前考虑的节点为(i),(i)所在块的右部横坐标为(q),扫描(M)的整块做处理。则我们要求矩形([(q,a_i+1),(p,p4)])内的点数。
二维差分后变成(g(p,p4)-g(p,a_i)-g(q,p4)+g(q,a_i))。
(g(p,p4))和(g(q,p4))贡献和(i)无关,显然可以用前面提到的二维前缀和求出(i)的个数。
由于(p4)贴在块的右端点上,所以可以用前面提到的(s)求。
(g(i,a_i))可以在块内维护一个前缀和(t),(t_i)表示(g(i,a_i)),找标号可以用以前的数组(f)。
(g(q,a_i))可以把这个块挂在(q)的块上。
这事实上是一些点有权值,要求一个左部贴着某个块的左部,右部贴着某个块的右部平面的点的权值和。
由于点权贴在块的右端点上,所以可以用前面提到的(s)求。
可以给每个块再维护一个前缀和,然后扫描每个当前询问包含的块,用(f)求出标号后用前缀和求出答案。
时间复杂度(O((n+m)sqrt{n})),感觉常数很大。
难度:中
lg7476
考虑标记永久化,在每个节点上用一个堆维护标记。
1操作就是区间加标记,3操作可以区间查询标记,每走到一个节点把答案和当前点的标记取最大值。
子树标记最大值可以轻松维护。
2操作有点麻烦,假设最大值为(x)。
在线段树上,我们可以把当前点拆成(log_2n)个区间,拆出的区间的祖先节点假如标记最大值(=x),则把祖先(=x)的标记弹出。
把祖先的区间和查询区间取交,把祖先的区间减去交区间后,插入这个值为(x)的这个区间。
在拆成线段树的区间后,我们可以在这个区间对应的点(p)上dfs,当(p)的子树没有(x)标记时(就是子树标记最大值不等于(x))就退出。
由于标记只会弹出一个,所以在可以弹出时就可以退出了。
时间复杂度是(O(nlog_2^2n+qlog_2n))的
难度:易