当前位置: 首页 > news >正文

题解:P9194 [USACO23OPEN] Triples of Cows P

更差的阅读体验


我们发现一棵树删掉一个点之后会在删掉点的位置形成一个团,这很坏。我们希望还能形成一棵树。

所以我们考虑对这个图建圆方树。

我们以 \(n\) 为根,这样这个点不会被删掉。然后假设方点 \(u\) 的儿子个数为 \(s_u\)

考虑题目要我们数的三元组 \((a, b, c)\) 的数量。假设圆点 \(a, b\) 中间是方点 \(x\)\(b, c\) 之间方点是 \(y\),那么考虑按照以下讨论来统计答案:

  1. \(x = y\)。那么枚举这个方点,在它的邻居中随便选三个点都可以。它有 \(s_x + 1\) 个邻居,那么方案数是 \((s_x + 1) s_x (s_x - 1)\)
  2. \(x \not = y\)\(x, y\) 都是 \(b\) 的儿子,如图。

那么我们要数的就是在 \(b\) 的孙子中挑选出两个圆点 \(a, c\)\(a, c\)\(b\) 的不同子树。那就是在 \(b\) 的孙子中随便挑两个的方案数,减去在每个子树里挑两个孙子的方案数。也就是

\[(\sum_{x \isin son_b} s_x) ^ 2 - \sum_{x \isin son_b} s_x ^ 2 \]

对于后半部分,对于所有 \(b\),每个 \(x\) 只会被计算一次,所以可以拆出来。

在这种情况下,我们需要知道一个圆点 \(u\) 的所有儿子的 \(s\) 之和。这个我们称为 \(S_u\),只有圆点有定义。在实现中我把 \(S\)\(s\) 存在同一个数组里。

  1. \(x \not = y\)\(x, y\) 都是 \(b\) 的儿子,如图。

我们不妨假设 \(b\) 的父亲是 \(x\),最后 \(\times 2\) 就能得到另一半的方案数。那么我们考虑在 \(x\) 处计算贡献。

首先我们要先选出 \(b\),然后再选出 \(y\),在 \(b, y\) 确定的情况下,选出 \(c\) 的方案数也就是 \(y\) 的儿子数量 \(s_y\)。然后我们还要选出 \(a\)。由于 \(x\)\(s_x + 1\) 个邻居,有一个是 \(b\) 已经被选择了,所以选 \(a\) 的方案数是 \(s_x\)。所以 \(x\) 的贡献是

\[2 s_x \sum_{b \isin son_x} \sum_{y \isin son_b} s_y \]

我们发现在这种情况下,我们需要知道一个方点孙子的 \(s\) 之和,不妨设 \(x\) 孙子的 \(s\) 之和为 \(t_x\)

所以综合以上三种情况,为了让式子比较好看,我们假设 \(f(x) = x^3 - x^2 - x\),那么答案就是

\[\sum_x(f(s_x) + 2s_x t_x) + \sum_b S_b^2 \]

\(x\) 是方点,\(b\) 是圆点。只要我们能动态维护 \(s_x, t_x, S_b\),这道题就做完了。


我们考虑删点的时候是在做什么。当我们删掉一个圆点,我们会把它邻居的所有方点合并,也就是把它的儿子全部合并到它的父亲上。

这个复杂度可能不太对,因为它的儿子这个时候可能有一些也是从下面合并上来的,所以合并次数之和不一定是 \(O(n)\) 的。但是我们发现我们可以在合并 \(v \to u\) 时,把合并产生的贡献挂在 \(u\) 上,类似于打标记,等下次 \(u\) 合并到另外一个结点时,把这个标记再复制到另外一个结点。

所以我们只需要对原圆方树上的点的儿子进行合并即可,也就是对没合并过的儿子进行合并。这样一个儿子只就合并一次,复杂度就对了。

我们一次删点 \(u\) 要删除 \(u\) 的每个儿子,并且要更新 \(u\) 的父亲,爷爷,曾祖父的权值。第一部分的和是 \(O(n)\) 的,第二部分是 \(O(1)\) 的。这一部分细节比较多,代码里有注释说每一步在做什么。

并查集维护即可。每次合并后更新答案。

那么这道题就做完了,复杂度 \(O(n \alpha(n))\)

#include<bits/stdc++.h>
#define endl '\n'
#define N 400006
using namespace std;
using i64=long long;
int n,s[N],t[N],f[N],fa[N];
vector<int> G[N]; i64 ans;
inline void add(int u,int v) {G[u].push_back(v),G[v].push_back(u);}
inline int find(int k) {return f[k]==k?k:f[k]=find(f[k]);}
void dfs(int u)
{for(int v:G[u])if(v!=fa[u]){fa[v]=u,dfs(v);if(u>n)s[u]++,t[u]+=s[v];else s[u]+=s[v];}
}
inline i64 fc(int x) {return -1ll*x*x-x+1ll*x*x*x;}
inline i64 calc(int i) {return fc(s[i])+2ll*s[i]*t[i];}
inline void del(int u)
{int ft=find(fa[u]),g=fa[ft];//去掉父亲和爷爷的贡献 ans-=calc(ft)+1ll*s[g]*s[g],s[g]-=s[ft],s[ft]--;//去掉自己的贡献 t[ft]-=s[u],ans-=1ll*s[u]*s[u],s[u]=0; int ss=-1;//ss 表示 u 的父亲的 s 增加了多少 //初始为 -1 是因为 u 的父亲的 s 减掉了 u 一个 for(int v:G[u])if(v!=fa[u])//把 u 的儿子方点 v 删掉,并入 u 的父亲f[v]=ft,s[ft]+=s[v],ss+=s[v],t[ft]+=t[v],ans-=calc(v),s[v]=t[v]=0;//u 的父亲 s 增加多少,u 的爷爷 s 就增加多少,u 的曾祖父的 t 就增加增加多少s[g]+=s[ft],ans+=calc(ft)+1ll*s[g]*s[g];//更新曾祖父 int gg=find(fa[fa[ft]]); t[gg]+=ss,ans+=2ll*s[gg]*ss; 
}
main()
{scanf("%d",&n);for(int i=1,u,v;i<n;i++)scanf("%d%d",&u,&v),add(u,i+n),add(v,i+n);dfs(n);for(int i=1;i<=n;i++)ans+=1ll*s[i]*s[i],f[i]=i;for(int i=n+1;i<n*2;i++)ans+=calc(i),f[i]=i;printf("%lld\n",ans);for(int i=1;i<n;i++)del(i),printf("%lld\n",ans);return 0;
}
/*
考虑建圆方树。
对于点对 (a, b, c),假设连接 ab 的方点是 x,连接 bc 的方点是 y。假设方点 i 的儿子个数为 s[i] 1. x = y,答案是 \sum _x (s[i]+1)s[i](s[i]-1),x 为方点 
2. x \not = y 且 x,y 都是 b 的儿子。答案是sum_{b 为圆点} ( (\sum_x s[x]) ^ 2 - \sum_x s[x] ^ 2) x 为 b 的儿子。
3. x \not = y 且不妨设 x 是 b 的父亲,y 是 b 的儿子,最后乘 2 即可。sum_{x 为方点} 2 s[x] \sum_b \sum_y s[y],b 为 x 的儿子,y 为 b 的儿子。 我们维护: 
方点 s[u]。 
圆点 s[u] 表示其儿子(都是方点)的 s[v] 之和。
t[u] 表示方点的儿子的 s[v] 之和。 圆方树删点用并查集维护即可。这也太难了。 看到一个比较方便的计算形式:
f(x) = x^3 - x^2 - x
ans = \sum_x( f(s[x]) + 2 s[x]t[x] ) + \sum_b s[b]^2
x 为方点,b 为圆点。是不是就做完了。 
*/
http://www.jsqmd.com/news/285219/

相关文章:

  • java_ssm41基于Java的教学仪器设备销售商城网站_o9b00--论文
  • QSettings遍历ini的key
  • Node.js 后端架构的“隐秘角落”:从 Fastify 引擎到类型系统的博弈
  • java_ssm42基于Java的服装穿搭信息管理系统的设计与实现_idea项目源码
  • tick 数据接入实战:从 tick 行情到系统节奏感
  • 学生心理健康测评系统任务书
  • AI 搜索话语权争夺战,上海geo优化公司排名盘点,源级引擎成企业战略首选
  • “新”意十足 · HarmonyOS模板组件(本次上新:求职、回收、旅游攻略模板;发票、估价等组件)
  • 芜湖抖音巨量广告+巨量本地推开户投流攻略:认准三十六行网络科技,全案运营助力精准获客
  • java_ssm43健身房管理系统的设计与实现天津大学_idea项目源码
  • “新”意十足 · HarmonyOS模板组件(功能增强:商城、美食、工具等模板;短视频、剪辑等组件)
  • 2026控油去屑防脱洗发水排行榜:WMP登顶,精准适配不同需求
  • java_ssm36在线课堂问答教学系统课件 作业考试_idea项目源码
  • java_ssm37在线音乐分享平台的设计与实现
  • 基于Java+SpringBoot+SSM宠物医院管理系统(源码+LW+调试文档+讲解等)/宠物医院管理软件/宠物医院信息管理系统/宠物医院服务平台/宠物医院管理方案/宠物医院运营系统
  • 密封性好的渣浆泵有哪些?三大渣浆泵品牌硬核实力大比拼
  • 环保的渣浆泵厂家推荐:石泵泵业提供高效和可靠的解决方案
  • 你的细胞在窃听:别给身体发“毒代码”
  • 国产操作系统主流品牌阵营解析:谁在定义市场?
  • java_ssm38基于BS架构的家庭理财管理系统的设计与实现_idea项目源码
  • 2026年2-3月国际机票最低价查询指南:如何高效锁定未来一个月的价格?
  • PCB加速度传感器在路噪及底盘NVH测试中的应用与型号推荐
  • java_ssm39基于B_S模式的小型房屋租赁系统的房东_t65a9--论文
  • SUM函数深度解析:从基础求和到多条件统计的完美跨越
  • 2026商标转让购买平台实测榜:综合评分9.9分的平台,标源100%可核验
  • 热销榜单:2026年高口碑修补防水涂料厂家推荐,满足各种工程需求
  • Gensors 压力扫描阀应用:燃气轮机燃烧室压差测量的“冗余智慧”
  • java_ssm40基于j2ee的问卷调查系统--论文
  • java_ssm34在线花卉鲜花商城销售系统的带支付_idea项目源码
  • 职场汇报真能决定升职加薪?那些会说话的人,早就赢在了起跑线上