zoukankan      html  css  js  c++  java
  • 一些ds题的题解

    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))
    难度:易

  • 相关阅读:
    485串口接线
    mvc3 升级mvc5
    VB连接ACCESS数据库,使用 LIKE 通配符问题
    VB6 读写西门子PLC
    可用的 .net core 支持 RSA 私钥加密工具类
    解决 Win7 远程桌面 已停止工作的问题
    解决 WinForm 重写 CreateParams 隐藏窗口以后的显示问题
    解决安装 .net framework 发生 extracting files error 问题
    CentOS7 安装配置笔记
    通过特殊处理 Resize 事件解决 WinForm 加载时闪烁问题的一个方法
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/15193254.html
Copyright © 2011-2022 走看看