Warning: session_start(): open(/tmp/sess_b80b06bf9dcfeef323d3609688174e71, O_RDWR) failed: No space left on device (28) in /data/wiki/inc/init.php on line 239

Warning: session_start(): Failed to read session data: files (path: ) in /data/wiki/inc/init.php on line 239

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/inc/auth.php on line 430

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/inc/actions.php on line 38

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/lib/tpl/dokuwiki/main.php on line 12
2020-2021:teams:legal_string:jxm2001:contest:ccpc_wannafly_winter_camp_day5 [CVBB ACM Team]

用户工具

站点工具


2020-2021:teams:legal_string:jxm2001:contest:ccpc_wannafly_winter_camp_day5

到此差别页面的链接

后一修订版
前一修订版
2020-2021:teams:legal_string:jxm2001:contest:ccpc_wannafly_winter_camp_day5 [2021/05/26 20:05]
jxm2001 创建
2020-2021:teams:legal_string:jxm2001:contest:ccpc_wannafly_winter_camp_day5 [2021/05/27 16:07] (当前版本)
jxm2001
行 2: 行 2:
  
 [[https://​ac.nowcoder.com/​acm/​contest/​4120|比赛链接]] [[https://​ac.nowcoder.com/​acm/​contest/​4120|比赛链接]]
 +
 +===== B. Bitset Master =====
 +
 +==== 题意 ====
 +
 +给定 $n$ 阶树和 $m$ 个操作。每个点 $u$ 维护一个集合 $S(u)$,初始时 $S(u)=\{u\}$。
 +
 +每次操作选定一条树边 $u\to v$,令 $S(u)=S(v)=\text{\old}(S(u)\cup S(v))$。
 +
 +对每个 $u$,输出有多少个 $v$ 满足 $u\in S(v)$。
 +
 +==== 题解 ====
 +
 +设 $m$ 次操作选择的边为 $e_1,​e_2\cdots e_m$。观察 $u\in S(v)$,这等价于序列 $\{e\}$ 中存在某个子序列 $e_{p_1},​e_{p_2}\cdots e_{p_k}$ 恰好是连接 $u,v$ 的路径。
 +
 +如果逆序操作,即序列变为 $e_{p_k},​e_{p_{k-1}}\cdots e_{p_1}$,则有 $v\in S(u)$。
 +
 +于是正序操作 $\sum_{v=1}^n [u\in S(v)]=$ 逆序操作 $\sum_{v=1}^n [v\in S(u)]=$ 逆序操作 $|S(u)|$。
 +
 +接下来考虑怎样维护 $|S(u)|$。根据容斥定理,有 $|S(u)\cup S(v)|=|S(u)|+|S(v)|-|S(u)\cap S(V)|$。
 +
 +对 $t\in S(u)\cap S(v)$,由于树形结构约束,必存在子序列 $e_{p_1},​e_{p_2}\cdots e_{p_k}$ 代表路径 $k\to \cdots v\to u$ 或  $k\to \cdots u\to v$。 
 +
 +于是不难发现 $|S(u)\cap S(V)|$ 恰好为上次合并 $S(u),S(v)$ 的结果,维护一下即可。时间复杂度 $O(n+m)$。
 +
 +<hidden 查看代码>​
 +<code cpp>
 +const int MAXN=5e5+5;
 +struct Edge{
 + int u,v,w;
 +}edge[MAXN];​
 +int c[MAXN],​p[MAXN];​
 +int main()
 +{
 + int n=read_int(),​m=read_int();​
 + _rep(i,​1,​n)c[i]=1;​
 + _for(i,​1,​n){
 + int u=read_int(),​v=read_int();​
 + edge[i]=Edge{u,​v,​0};​
 + }
 + _for(i,​0,​m)
 + p[i]=read_int();​
 + for(int i=m-1;​i>​=0;​i--){
 + int u=edge[p[i]].u,​v=edge[p[i]].v,​cc=c[u]+c[v]-edge[p[i]].w;​
 + c[u]=cc,​c[v]=cc,​edge[p[i]].w=cc;​
 + }
 + _rep(i,​1,​n)
 + space(c[i]);​
 + return 0;
 +}
 +</​code>​
 +</​hidden>​
 +
 +===== C. Self-Adjusting Segment Tree =====
 +
 +==== 题意 ====
 +
 +给定线段树的 $m$ 次区间查询操作,要求构造一棵维护区间 $[1,n]$ 的特殊线段树。
 +
 +使得查询操作访问结点的次数最少的结点并输出访问结点的次数。
 +
 +==== 题解 ====
 +
 +不难得到 $\text{dp}$ 方程
 +
 +$$
 +\text{dp}(i,​j)=\min(\text{dp}(i,​k)+\text{dp}(k+1,​j)+w(i,​j))
 +$$
 +
 +然后考虑依次处理每个询问 $[ql,qr]$ 对 $w(i,j)$ 的贡献。不难发现当 $[i,j]$ 与 $[ql,qr]$ 相交但 $[i,​j]\not\subseteq [ql,qr]$ 时询问贡献为 $1$。
 +
 +问题在于 $[i,​j]\subseteq [ql,qr]$ 询问对 $w(i,j)$ 的贡献与询问是否包含 $[i,j]$ 区间的祖结点有关。
 +
 +有结论任意二叉树的叶子结点数 $=$ 非叶子结点数 $+1$,而线段树恰好为二叉树。
 +
 +于是不妨转化思路令 $[i,​i]\subseteq [ql,qr]$ 得到贡献 $1$,令 $[i,j](i\lt j)\subseteq [ql,qr]$ 得到贡献 $-1$。
 +
 +于是 $\text{dp}$ 过程中如果划分区间得到 $[i,​j]\subseteq [ql,​qr]$,则 $[i,j]$ 的子树的总贡献恰好为 $1$。
 +
 +对应每个询问对 $w(i,j)$ 的贡献,差分维护即可,时间复杂度 $O(n^3+m)$。
 +
 +<hidden 查看代码>​
 +<code cpp>
 +const int MAXN=505;
 +const LL inf=1e16;
 +LL d1[MAXN],​d2[MAXN][MAXN],​w[MAXN][MAXN],​dp[MAXN][MAXN];​
 +void update(int l1,int l2,int r1,int r2,int v){
 + d2[l1][r1]+=v;​
 + d2[l1][r2+1]-=v;​
 + d2[l2+1][r1]-=v;​
 + d2[l2+1][r2+1]+=v;​
 +}
 +int main()
 +{
 + int n=read_int(),​m=read_int();​
 + while(m--){
 + int ql=read_int(),​qr=read_int();​
 + update(1,​ql-1,​ql,​qr,​1);​
 + update(1,​qr,​qr+1,​n,​1);​
 + update(ql,​qr,​ql,​qr,​-1);​
 + d1[ql]+=2;​
 + d1[qr+1]-=2;​
 + }
 + _rep(i,​1,​n)_rep(j,​1,​n)
 + w[i][j]=d2[i][j]+w[i-1][j]+w[i][j-1]-w[i-1][j-1];​
 + _rep(i,​1,​n){
 + d1[i]+=d1[i-1];​
 + w[i][i]+=d1[i];​
 + }
 + _rep(i,​1,​n)_rep(j,​1,​n){
 + if(i==j)
 + dp[i][j]=w[i][j];​
 + else
 + dp[i][j]=inf;​
 + }
 + for(int i=n;​i;​i--)_rep(j,​i+1,​n)_for(k,​i,​j)
 + dp[i][j]=min(dp[i][j],​dp[i][k]+dp[k+1][j]+w[i][j]);​
 + enter(dp[1][n]);​
 + return 0;
 +}
 +</​code>​
 +</​hidden>​
  
 ===== J. Xor on Figures ===== ===== J. Xor on Figures =====
2020-2021/teams/legal_string/jxm2001/contest/ccpc_wannafly_winter_camp_day5.1622030758.txt.gz · 最后更改: 2021/05/26 20:05 由 jxm2001