题目链接

http://codeforces.com/contest/482/problem/E

题解

T2智商题T3大LCT题,我一个也不会= =

CF的标算好像是分块?反正现在LCT都普及了就用LCT好了。

首先算期望推个式子,易得答案为\(\sum_u a[u](sz[u]^2-\sum_{v\in son[u]} sz[v]^2)\) (\(sz\)为子树大小),令求和的那个东西等于\(f[u]\)

并且如果往一个\(u\)里新添一个儿子\(v\),增添后的子树大小是\(sz[v]\), 那么新增的答案是\(2a[u]sz[v](sz[u]-sz[v])\)

然后我们要支持换父亲,动态维护这个东西

后面的就是莽上一个LCT。

这个只能详见代码,解释一下代码里变量的含义

对于一个Splay结构体\(u\):

\(ans\): 这个点Splay的子树中所有点的\(f\)之和。Splay的根的\(ans\)就是要求的答案。

\(sz01\): 这个点所有虚子树的大小之和加上本身的\(1\)。(\(sz\)是原树中子树大小)

\(sz02\): 这个点本身所有虚子树的大小平方和,不包括本身。

\(ans0\): 这个点本身所有虚儿子的\(ans\)之和。

\(sz11\): 这个点所有实儿子和虚儿子的大小之和。

\(sum\): 这个点及其所有实儿子\(v\)的\(sz01[v]\times a[v]\)之和。

这些变量看起来有些匪夷所思,那么我们看下怎么维护。

首先,所有对虚儿子求和的变量(也就是名字里带0的三个)都在access时处理,pushup时无需处理。

现在考虑pushup那个函数,前两行处理的是\(sz11\)和\(sum\), 这个根据定义求就行,也没有什么好说的。

后四行是重点——\(ans\)的更新。

我们把\(ans[u]\)分了四部分统计。(选两个点\(x\)和\(y\)求\(a[lca(x,y)]\)之和)

第一部分: 两个点都选在\(u\)的祖先(splay左子树内),或都选在splay右子树内,或都选在\(u\)的同一棵虚子树内。

  1. spl[u].ans = spl[ls].ans+spl[u].ans0+spl[rs].ans;

第二部分: 两个点选在\(u\)的两棵不同虚子树内。

  1. spl[u].ans += (spl[u].sz01*spl[u].sz01-spl[u].sz02)*a[u];

第三部分: 两个点之一选在\(u\)的虚子树内,另一个点选在\(u\)的splay右子树内。这样LCA一定是\(u\).

  1. spl[u].ans += 2ll*spl[u].sz01*spl[rs].sz11*a[u];

第四部分: 两个点之一选在\(u\)的祖先(splay左子树)或其虚子树内,另一个选在\(u\)的整个splay子树及子树内所有点的虚子树去掉\(u\)上方(splay左子树内及其虚子树)的部分,也就是\(u\)及其下方(splay右子树内)所有点及其虚子树内。

  1. spl[u].ans += 2ll*spl[ls].sum*(spl[u].sz11-spl[ls].sz11);

于是就做完了。(第四部分确实有点复杂)

最后膜拜一发考场切此题的新初三巨佬

zjr nb!

代码

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<iostream>
  4. #define llong long long
  5. using namespace std;
  6. void read(int &x)
  7. {
  8. int f=1;x=0;char s=getchar();
  9. while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
  10. while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
  11. x*=f;
  12. }
  13. const int N = 1e5;
  14. struct SplayNode
  15. {
  16. int son[2],fa; llong sz01,sz11,sz02,sum,ans0,ans;
  17. } spl[N+3];
  18. int fa[N+3];
  19. llong a[N+3];
  20. int n,q;
  21. bool isroot(int u) {return spl[spl[u].fa].son[0]!=u && spl[spl[u].fa].son[1]!=u;}
  22. void pushup(int u)
  23. {
  24. int ls = spl[u].son[0],rs = spl[u].son[1];
  25. spl[u].sz11 = spl[ls].sz11+spl[u].sz01+spl[rs].sz11;
  26. spl[u].sum = spl[ls].sum+spl[rs].sum+spl[u].sz01*a[u];
  27. spl[u].ans = spl[ls].ans+spl[u].ans0+spl[rs].ans;
  28. spl[u].ans += (spl[u].sz01*spl[u].sz01-spl[u].sz02)*a[u];
  29. spl[u].ans += 2ll*spl[u].sz01*spl[rs].sz11*a[u];
  30. spl[u].ans += 2ll*spl[ls].sum*(spl[u].sz11-spl[ls].sz11);
  31. }
  32. void rotate(int u)
  33. {
  34. int x = spl[u].fa,y = spl[x].fa;
  35. spl[u].fa = y;
  36. if(!isroot(x)) {spl[y].son[x==spl[y].son[1]] = u;}
  37. int dir = u==spl[x].son[0];
  38. spl[x].son[dir^1] = spl[u].son[dir];
  39. if(spl[u].son[dir]) {spl[spl[u].son[dir]].fa = x;}
  40. spl[u].son[dir] = x; spl[x].fa = u;
  41. pushup(x); pushup(u);
  42. }
  43. void splaynode(int u)
  44. {
  45. while(!isroot(u))
  46. {
  47. int x = spl[u].fa,y = spl[x].fa;
  48. if(!isroot(x)) {x==spl[y].son[1] ^ u==spl[x].son[1] ? rotate(u) : rotate(x);}
  49. rotate(u);
  50. }
  51. pushup(u);
  52. }
  53. void access(int u)
  54. {
  55. for(int i=0; u; i=u,u=spl[u].fa)
  56. {
  57. splaynode(u);
  58. int ls = spl[u].son[0],rs = spl[u].son[1];
  59. spl[u].sz01 += spl[rs].sz11;
  60. spl[u].sz02 += spl[rs].sz11*spl[rs].sz11;
  61. spl[u].ans0 += spl[rs].ans; //not ans0
  62. rs = spl[u].son[1] = i;
  63. spl[u].sz01 -= spl[rs].sz11;
  64. spl[u].sz02 -= spl[rs].sz11*spl[rs].sz11;
  65. spl[u].ans0 -= spl[rs].ans;
  66. pushup(u);
  67. }
  68. }
  69. void link(int u,int v)
  70. {
  71. access(v); splaynode(v);
  72. access(u); splaynode(u); //in order to pushup
  73. spl[u].sz01 += spl[v].sz11;
  74. spl[u].sz02 += spl[v].sz11*spl[v].sz11;
  75. spl[u].ans0 += spl[v].ans;
  76. spl[v].fa = u;
  77. pushup(u);
  78. }
  79. void cut(int u,int v)
  80. {
  81. access(u); splaynode(u);
  82. splaynode(v); //v is in the virtual subtree of u
  83. spl[u].sz01 -= spl[v].sz11;
  84. spl[u].sz02 -= spl[v].sz11*spl[v].sz11;
  85. spl[u].ans0 -= spl[v].ans;
  86. spl[v].fa = 0;
  87. pushup(u);
  88. }
  89. bool isanc(int u,int v) //if u is ancestor of v
  90. {
  91. access(v); splaynode(v);
  92. splaynode(u);
  93. if(!isroot(v)) return true;
  94. return false;
  95. }
  96. void printans(llong x)
  97. {
  98. double ans = (double)x/(double)n/(double)n;
  99. printf("%.12lf\n",ans);
  100. }
  101. int main()
  102. {
  103. scanf("%d",&n);
  104. for(int i=2; i<=n; i++) scanf("%d",&fa[i]);
  105. for(int i=1; i<=n; i++) scanf("%I64d",&a[i]);
  106. for(int i=1; i<=n; i++) spl[i].sz11 = spl[i].sz01 = 1ll,spl[i].ans = spl[i].sum = a[i];
  107. for(int i=2; i<=n; i++)
  108. {
  109. link(fa[i],i);
  110. }
  111. access(1); splaynode(1);
  112. printans(spl[1].ans);
  113. scanf("%d",&q);
  114. for(int i=1; i<=q; i++)
  115. {
  116. char opt[5]; scanf("%s",opt+1);
  117. if(opt[1]=='P')
  118. {
  119. int x,y; scanf("%d%d",&x,&y);
  120. if(isanc(x,y)) {swap(x,y);}
  121. cut(fa[x],x);
  122. fa[x] = y;
  123. link(fa[x],x);
  124. access(1); splaynode(1);
  125. printans(spl[1].ans);
  126. }
  127. else if(opt[1]=='V')
  128. {
  129. int x; llong y; scanf("%d%I64d",&x,&y);
  130. access(x); splaynode(x);
  131. a[x] = y;
  132. pushup(x);
  133. printans(spl[x].ans);
  134. }
  135. }
  136. return 0;
  137. }

Codeforces 482E ELCA (LCT)的更多相关文章

  1. CF数据结构练习

    1. CF 438D The Child and Sequence 大意: n元素序列, m个操作: 1,询问区间和. 2,区间对m取模. 3,单点修改 维护最大值, 取模时暴力对所有>m的数取 ...

  2. Codeforces 1172E Nauuo and ODT [LCT]

    Codeforces ZROI那题是这题删掉修改的弱化版--ZROI还我培训费/px 思路 按照套路,我们考虑每种颜色的贡献,然后发现不包含某种颜色的路径条数更容易数,就是删掉该颜色的点后每个连通块大 ...

  3. Codeforces 1137F Matches Are Not a Child's Play [LCT]

    Codeforces 很好,通过这题对LCT的理解又深了一层. 思路 (有人说这是套路题,然而我没有见过/kk) 首先发现,删点可以从根那里往下删,非常难受,所以把权值最大的点提为根. 然后考虑\(x ...

  4. Codeforces 1137F - Matches Are Not a Child's Play(LCT)

    Codeforces 题面传送门 & 洛谷题面传送门 考虑将一个点 \(x\) 的编号变为当前所有点编号最大值 \(+1\) 会对每个点的删除时间产生怎么样的影响.由于编号最大的点肯定是最后一 ...

  5. Codeforces 1109F - Sasha and Algorithm of Silence's Sounds(LCT)

    Codeforces 题面传送门 & 洛谷题面传送门 讲个笑话,这题是 2020.10.13 dxm 讲题时的一道例题,而我刚好在一年后的今天,也就是 2021.10.13 学 LCT 时做到 ...

  6. CodeForces gym Nasta Rabbara lct

    Nasta Rabbara 题意:简单来说就是, 现在有 n个点, m条边, 每次询问一个区间[ l ,  r ], 将这个区间的所有边都连上, 如果现在的图中有奇数环, 就输出 “Impossibl ...

  7. Codeforces Round #539 (Div. 1) 1109F. Sasha and Algorithm of Silence's Sounds LCT+线段树 (two pointers)

    题解请看 Felix-Lee的CSDN博客 写的很好,不过最后不用判断最小值是不是1,因为[i,i]只有一个点,一定满足条件,最小值一定是1. CODE 写完就A,刺激. #include <b ...

  8. 【CF 482E】ELCA

    题意 题解 50pts 由于这题 \(2s\),所以可以信仰一波,暴力修改.查询. 暴力修改的复杂度是 \(O(n)\),暴力查询的复杂度是 \(O(n^2)\). 但不难发现可以通过记录子树大小来优 ...

  9. 【杂题】[CodeForces 1172E] Nauuo and ODT【LCT】【口胡】

    Description 给出一棵n个节点的树,每个点有一个1~n的颜色 有m次操作,每次操作修改一个点的颜色 需要在每次操作后回答树上\(n^2\)条路径每条路径经过的颜色种类数和. \(n,m< ...

随机推荐

  1. JAVAEE 7 api.chm

    JAVAEE 7 api.chm 链接:https://pan.baidu.com/s/1LUD3oam5B-Hp8tdpfQYk2w 提取码:x1kc

  2. 动态树(LCT、Top Tree、ETT)

    LCT Upd: 一个细节:假如我们要修改某个节点的数据,那么要先把它makeroot再修改,改完之后pushup. LCT是一种维护森林的数据结构,本质是用Splay维护实链剖分. 实链剖分大概是这 ...

  3. FastDFS集群部署(转载 写的比较好)

    FastDFS集群部署   之前介绍过关于FastDFS单机部署,详见博文:FastDFS+Nginx(单点部署)事例 下面来玩下FastDFS集群部署,实现高可用(HA) 服务器规划: 跟踪服务器1 ...

  4. CF407D Largest Submatrix 3

    cf luogu 被自己菜到自闭了/kk 既然是子矩阵,那么惯用套路为枚举矩阵上下边界,然后\(O(n)\)扫描求解.这题里要从左往右枚举右端点,然后看左端点最多能放到哪,那就对于每个数求出在上下边界 ...

  5. 深入理解hive基础学习

    Hive 是什么?  1.Hive 是基于 Hadoop处理结构化数据的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类 SQL 查询功能. 2.Hive 利用 HDFS 存储数据 ...

  6. 01 初识HTML

    HTML是什么? 超文本标记语言(Hypertext Markup Language, HTML)是一种用于创建网页的标记语言. 本质上是浏览器可识别的规则,我们按照规则写网页,浏览器根据规则渲染我们 ...

  7. 浅尝https

    HTTPS http超文本传输协议,所以的东西都是明文传输,容易被拦截,被攻击,我们希望能对通话内容进行加密,那么因此而生,出现了https https:在http的基础上新增加了SSL层 先放图 / ...

  8. 黑马java课程视频java学习视频

    资料获取方式,关注公总号RaoRao1994,查看往期精彩-所有文章,即可获取资源下载链接 更多资源获取,请关注公总号RaoRao1994

  9. EF报错:对一个或多个实体的验证失败(Entity Framework 强制转换失败数据异常处理方法)

    1.使用MVC和EF,在保存数据的时候报错:System.Data.Entity.Validation.DbEntityValidationException: 对一个或多个实体的验证失败.有关详细信 ...

  10. 小米Air 13.3 安装Arch Linux

    0. 前言 最近新买了一台小米Air 13.3,除了但键盘手感外都比较满意.我比较喜欢折腾Linux,但又不想放弃原有的Windows 10 Home,于是在原有的windows 10基础上再安装了A ...