2022.7.22 做题记录

为啥昨天没发做题记录呢

因为昨天颓了一天就写了一个题,就酱

CF246E Blood Cousins Return Present 6

给定 \(n\) 个节点的一片森林,每个节点上有一个字符串。

\(m\) 次询问,每次给出 \(v,k\),你需要输出 \(v\) 子树内深度为 \(d_v+k\) 的节点上有多少个不同的字符串。

其中 \(d_u\) 表示 \(u\) 的深度。\(1\le n,m\le 10^5\)

套路地拆出来每一层的节点,按照 \(\text{DFS}\) 序排序,现在相当于查询一个区间内去重后的元素个数。

\(p_i\)\(i\) 这一字符串上一次出现的位置,转化为二维数点,离线后用树状数组处理即可。

AC Code

Luogu8149 泪光 | Tears Future 7.5

原题题意有点缝合的感觉,这里给出转化后的题意:

\(n\) 个变量 \(v_1,\cdots,v_n\),现在有 \(m\) 次操作:

  • 1 a b c d:已知一个新条件:若 \(v_a=v_b\),则 \(v_c=v_d\)
  • 2 a b:已知一个新条件:\(v_a=v_b\)
  • 3 a b:询问是否能确定 \(v_a,v_b\) 恒相等。
  • 4 b:询问有多少个 \(a\) 满足:能够确定 \(v_a=v_b\)

\(1\le n,m\le 6\times 10^5\)。吐槽:为啥正解 \(O(n\log ^2n)\) 还给个这么大的范围啊 QwQ

不难发现条件二相当于连边,两个询问分别是「查询两点是否连通」以及「查询某点所在连通块大小」。

对于第一种条件,我们分两种情况讨论:

  • 如果 \(a,b\) 已经连通,那么直接连接 \(c,d\) 即可。
  • 否则,我们可以在每个连通块处维护一个 \(\texttt{std::multiset}\),里面存上若干三元组 \((b,u,v)\),表示若该连通块和 \(b\) 之间要连一条边,那么 \(u,v\) 也要连一条边。在连边时我们遍历较小的那个 \(\texttt{multiset}\),如果发现了满足条件的三元组就在对应的 \(u,v\) 之间连边。这个过程类似递归,不过我们可以使用队列实现,减小常数。连边之后我们将较小的 \(\texttt{multiset}\) 与较大的那个合并即可。

由于每个三元组只会被合并 \(O(\log n)\) 次,时间复杂度为 \(O(n\log ^2n)\)AC Code

SP21615 NAJPWG - Playing with GCD Present 7.0

\(T\) 组询问,每次给出正整数 \(n\),求

\[\sum_{i=1}^n\sum_{j=i}^n[\gcd(i,j)>1] \]

\(1\le n,T\le 10^5\)

萌萌推式子题

交换求和顺序

\[\sum_{i=1}^n\sum_{j=1}^{i}[\gcd(i,j)>1] \]

简单容斥

\[\sum_{i=1}^ni-\left(\sum_{j=1}^i[\gcd(i,j)=1]\right) \]

发现后面就是 \(\varphi(i)\),所以变为求 \(i-\varphi(i)\) 的前缀和

随便预处理一下就完事了,\(O(n)-O(1)\)AC Code

推式子题真好玩,明天再来一道

posted @ 2022-07-22 21:22  云浅知处  阅读(33)  评论(0编辑  收藏  举报