QWQ神仙题啊(据说是今年第一次出现圆方树的地方)

首先根据题目,我们就是求对于每一个路径\((s,t)\)他的贡献就是两个点之间的点数,但是图上问题我并没有办法很好的解决。。。

这时候考虑圆方树,我们将圆方树建出来之后,

我们令方点的权值是他所连接的圆点之和,圆点的权值是\(-1\)。

这里之所以让圆点的贡献是-1,是为了方便表示路径的贡献(不然貌似比较复杂)。

如果我们这么赋值的话,那么一个条路经的贡献就应该是点权之和。

QWQ可惜枚举两个端点是\(O(n^2)\)复杂度的

那么这时候,我们就可以直接考虑每个点作为中心的贡献,那么他的贡献就应该是:

子树外到子树内的贡献+子树之间的贡献。

那么我们只需要一边\(dfs\),一边维护\(size\)并更新\(ans\)就行

  1. void dfs(int x)
  2. {
  3. vis[x]=1;
  4. int tmp=0;
  5. if (x<=n) tmp=1;
  6. for (int i=point[x];i;i=nxt[i])
  7. {
  8. int p = to[i];
  9. if (vis[p]) continue;
  10. dfs(p);
  11. ans=ans+tmp*size[p]*val[x];
  12. tmp+=size[p];
  13. // cout<<ans<<endl;
  14. }
  15. ans=ans+size[x]*(sum-size[x])*val[x];
  16. }

不过要注意的是,最后的\(ans\)需要乘2,因为是双向的

而且图不一定联通!!!!!

  1. // luogu-judger-enable-o2
  2. #include<iostream>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<cmath>
  7. #include<queue>
  8. #include<map>
  9. #include<set>
  10. #define mk makr_pair
  11. #define ll long long
  12. #define int long long
  13. using namespace std;
  14. inline int read()
  15. {
  16. int x=0,f=1;char ch=getchar();
  17. while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  18. while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  19. return x*f;
  20. }
  21. const int maxn = 3e5+1e2;
  22. const int maxm = 2*maxn;
  23. int point[maxn],nxt[maxm],to[maxm];
  24. int point1[maxn],nxt1[maxm],to1[maxm];
  25. int cnt,cnt1;
  26. int n,m;
  27. int f[maxn],val[maxn],size[maxn],g[maxn];
  28. int vis[maxn];
  29. int top,st[maxn];
  30. int low[maxn],dfn[maxn];
  31. int ans;
  32. void addedge(int x,int y)
  33. {
  34. nxt[++cnt]=point[x];
  35. to[cnt]=y;
  36. point[x]=cnt;
  37. }
  38. void addedge1(int x,int y)
  39. {
  40. nxt1[++cnt1]=point1[x];
  41. to1[cnt1]=y;
  42. point1[x]=cnt1;
  43. }
  44. int tot,num;
  45. void tarjan(int x,int fa)
  46. {
  47. dfn[x]=low[x]=++tot;
  48. st[++top]=x;
  49. for (int i=point1[x];i;i=nxt1[i])
  50. {
  51. int p = to1[i];
  52. if (p==fa) continue;
  53. if (!dfn[p])
  54. {
  55. tarjan(p,x);
  56. low[x]=min(low[x],low[p]);
  57. if (low[p]>=dfn[x])
  58. {
  59. ++num;
  60. addedge(num,x);
  61. addedge(x,num);
  62. val[num]++;
  63. do{
  64. addedge(st[top],num);
  65. addedge(num,st[top]);
  66. val[num]++;
  67. top--;
  68. }while (st[top+1]!=p);
  69. }
  70. }
  71. else
  72. low[x]=min(low[x],dfn[p]);
  73. }
  74. }
  75. void dp(int x,int faa)
  76. {
  77. if (x<=n)
  78. size[x]=1;
  79. for (int i=point[x];i;i=nxt[i])
  80. {
  81. int p = to[i];
  82. if (p==faa) continue;
  83. dp(p,x);
  84. size[x]+=size[p];
  85. }
  86. //cout<<x<<" "<<size[x]<<endl;
  87. }
  88. int sum;
  89. void dfs(int x)
  90. {
  91. vis[x]=1;
  92. int tmp=0;
  93. if (x<=n) tmp=1;
  94. for (int i=point[x];i;i=nxt[i])
  95. {
  96. int p = to[i];
  97. if (vis[p]) continue;
  98. dfs(p);
  99. ans=ans+tmp*size[p]*val[x];
  100. tmp+=size[p];
  101. // cout<<ans<<endl;
  102. }
  103. ans=ans+size[x]*(sum-size[x])*val[x];
  104. }
  105. signed main()
  106. {
  107. n=read(),m=read();
  108. num=n;
  109. for (int i=1;i<=n;i++) val[i]=-1;
  110. for (int i=1;i<=m;i++)
  111. {
  112. int x=read(),y=read();
  113. addedge1(x,y);
  114. addedge1(y,x);
  115. }
  116. for (int i=1;i<=n;i++)
  117. {
  118. if(!dfn[i]) tarjan(i,0);
  119. }
  120. for (int i=1;i<=n;i++)
  121. {
  122. if(!vis[i])
  123. {
  124. dp(i,0);
  125. sum=size[i];
  126. dfs(i);
  127. }
  128. }
  129. cout<<ans*2<<endl;
  130. return 0;
  131. }

洛谷4630APIO2018铁人两项(圆方树+dp)的更多相关文章

  1. 洛谷P4630 铁人两项--圆方树

    一道很好的圆方树入门题 感谢PinkRabbit巨佬的博客,讲的太好啦 首先是构建圆方树的代码,也比较好想好记 void tarjan(int u) { dfn[u] = low[u] = ++dfn ...

  2. [BZOJ5463][APIO2018]铁人两项(圆方树DP)

    题意:给出一张图,求满足存在一条从u到v的长度大于3的简单路径的有序点对(u,v)个数. 做了上一题[HDU5739]Fantasia(点双连通分量+DP),这个题就是一个NOIP题了. 一开始考虑了 ...

  3. [APIO2018] Duathlon 铁人两项 圆方树,DP

    [APIO2018] Duathlon 铁人两项 LG传送门 圆方树+简单DP. 不会圆方树的话可以看看我的另一篇文章. 考虑暴力怎么写,枚举两个点,答案加上两个点之间的点的个数. 看到题面中的一句话 ...

  4. [APIO2018]铁人两项 --- 圆方树

     [APIO2018] 铁人两项 题目大意: 给定一张图,问有多少三元组(a,b,c)(a,b,c 互不相等)满足存在一条点不重复的以a为起点,经过b,终点为c的路径 如果你不会圆方树 ------- ...

  5. [APIO2018]铁人两项 [圆方树模板]

    把这个图缩成圆方树,把方点的权值设成-1,圆点的权值设成点双的size,算 经过这个点的路径的数量*这个点的点权 的和即是答案. #include <iostream> #include ...

  6. [APIO2018]铁人两项——圆方树+树形DP

    题目链接: [APIO2018]铁人两项 对于点双连通分量有一个性质:在同一个点双里的三个点$a,b,c$,一定存在一条从$a$到$c$的路径经过$b$且经过的点只被经过一次. 那么我们建出原图的圆方 ...

  7. 【Luogu4630】【APIO2018】 Duathlon 铁人两项 (圆方树)

    Description ​ 给你一张\(~n~\)个点\(~m~\)条边的无向图,求有多少个三元组\(~(x, ~y, ~z)~\)满足存在一条从\(~x~\)到\(~z~\)并且经过\(~y~\)的 ...

  8. LOJ 2587 「APIO2018」铁人两项——圆方树

    题目:https://loj.ac/problem/2587 先写了 47 分暴力. 对于 n<=50 的部分, n3 枚举三个点,把图的圆方树建出来,合法条件是 c 是 s -> f 路 ...

  9. loj2587 「APIO2018」铁人两项[圆方树+树形DP]

    主要卡在一个结论上..关于点双有一个常用结论,也经常作为在圆方树/简单路径上的良好性质,对于任意点双内互不相同的三点$s,c,t$,都存在简单路径$s\to c\to t$,证明不会.可以参见clz博 ...

随机推荐

  1. 一文彻底弄懂this关键字用法

    哈喽,大家好,我是指北君. 介绍完 native.static.final 关键字后,指北君再接再厉,接着为大家介绍另一个常用的关键字--this. this 也是Java中的一个关键字,在<J ...

  2. Learning to Compare: Relation Network for Few-Shot Learning 论文笔记

    主要原理: 和Siamese Neural Networks一样,将分类问题转换成两个输入的相似性问题. 和Siamese Neural Networks不同的是: Relation Network中 ...

  3. MySQL alter table时执行innobackupex全备再看Seconds_Behind_Master

    1.场景描述 早上7:25 接到Report中心同学告警,昨天业务报表数据没有完整跑出来,缺少500位业务员的数据,并且很快定位到,缺少的是huabei_order库上的数据.Report中心的数据是 ...

  4. RHEL7.2系统下的软件管理(yum)、本地yum源和网络yum源的搭建

    在Liunx系统中,rpm和yum都可以安装软件,但rpm存在安装软件的依赖性,yum安装软件需要yum源 1.yum yum install softwarename ##安装 yum repoli ...

  5. JS 之 每日一题 之 算法 ( 有多少小于当前数字的数字 )

    给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目. 换而言之,对于每个 nums[i] 你必须计算出有效的 j 的数量,其中 j 满足 j != i 且 ...

  6. etcd学习(9)-etcd中的存储实现

    etcd中的存储实现 前言 V3和V2版本的对比 MVCC treeIndex 原理 MVCC 更新 key MVCC 查询 key MVCC 删除 key 压缩 周期性压缩 版本号压缩 boltdb ...

  7. 九、Abp vNext 基础篇丨评论聚合功能

    介绍 评论本来是要放到标签里面去讲的,但是因为上一章东西有点多了,我就没放进去,这一章单独拿出来,内容不多大家自己写写就可以,也算是对前面讲解的一个小练习吧. 相关注释我也加在代码上面了,大家看看代码 ...

  8. 在 Docker 的 CentOS7 镜像 中安装 mysql

    在 Docker 的 CentOS7 镜像 中安装 mysql 本来以为是个很简单的过程居然折腾了这么久,之前部署云服务器时也没有好好地记录,因此记录下. 特别提醒:本文的操作环境是在 Docker ...

  9. 第七章:网络优化与正则化(Part1)

    任何数学技巧都不能弥补信息的缺失. --科尼利厄斯·兰佐斯(Cornelius Lanczos) 匈牙利数学家.物理学家 文章相关 1 第七章:网络优化与正则化(Part1) 2 第七章:网络优化与正 ...

  10. vscode快速添加引号 批量增加引号(用于批量格式化代码)

    一.在浏览器中将Params复制到pycharm的py文件中 二.选中需要添加引号的部分,Ctrl+H 调出替换工具栏 三.填写正则表达式 (.*?): (.*) '$1':'$2', 右侧注意点击使 ...