题意

原意简述版

有 \(n\) 个公司,每个公司在某社交媒体拥有一个粉丝专页。该社交媒体推出了“关注”功能,每个粉丝专页必须“关注”一个粉丝专页,保证不会有自己关注自己和互关的事情出现。第 \(i\) 个公司的粉丝专页有 \(v_i\) 位订阅者。每个粉丝专页上都有一些广告,分别来自:

  • 该粉丝专页的所有者公司
  • 该粉丝专页“关注”的粉丝专页的所有者公司
  • “关注”该粉丝专页的粉丝专页的所有者公司

当第 \(i\) 个公司的粉丝专页上有 \(k\) 条广告时,每条广告都会被点击 \(\left\lfloor\dfrac {v_i}k\right\rfloor\) 次。每位订阅者会点一条广告,所以多余的还没有点广告的订阅者就会全部点该粉丝专页的所有者公司的广告。每一位订阅者的点击会为广告的所有者公司带来 \(1\) 的收益。现在要求你支持以下三个操作:

  1. 1 x y 让第 \(x\) 个公司的粉丝专页改为“关注”第 \(y\) 个公司的粉丝专页。
  2. 2 x 查询假如每位订阅者按照上述规则进行一次点击,第 \(x\) 个公司的收益。
  3. 3 查询假如每位订阅者按照上述规则进行一次点击,收益最低的公司的收益和收益最高的公司的收益。

压缩版

\(n\) 个带权点,每个点有一条出边。不会出现自环和互为出边指向点。要查询的值被称为收益。设和点 \(u\) 直接有边相连(与边的方向无关)的点数为 \(k_u\),点 \(u\) 的权值为 \(v_u\)。则每一个和 \(u\) 直接有边相连的点收益增加 \(\left\lfloor\dfrac {v_u}{k_u+1}\right\rfloor\),对自己贡献 \(v_u-k_u\times\left\lfloor\dfrac {v_u}{k_u+1}\right\rfloor\)。注意每个点只会在每个独立询问时对周围的点有收益贡献,收益不会保留到下次询问继续累加,而是会清空。三种操作:

  1. 1 x y 修改点 \(x\) 的出边指向点为 \(y\)。
  2. 2 x 查询点 \(x\) 的收益。
  3. 3 查询所有点中的最小收益和最大收益。

思路

暴力怎么做?修改时暴力修改对周围所有点的贡献,查询时直接输出或枚举所有点求最值。修改最劣 \(O(n)\)。

仔细考虑,发现这个 \(O(n)\) 来自于该点连接的边数,而边数是 \(O(n)\) 级别的。也就是说,随机下均摊是 \(O(1)\) 级别的。那我们有没有方法可以平衡复杂度呢?

要做到严格 \(O(1)\),可以想到要强制某点修改时只对相连的边中 \(O(1)\) 条边进行操作,其他的部分在查询时另行 \(O(1)\) 查询。

这时我们就发现每个点只有一条出边,看作基环树就可以理解为每个点只有一个父亲。那么我们就强制他只处理对其父亲的贡献,而对儿子的贡献等查询儿子时再计算。这样一来,每个点只有一个父亲则修改父亲 \(O(1)\),查询时也只需要加上父亲的贡献。这下就 \(O(n)\) 解决前两个操作了。(很多大佬能一眼看出这是个经典 trick:所有相连点都会造成贡献时,儿子的贡献和父亲的贡献分开计算。)

如何处理 3 操作?暴力开 set 维护或者暴力扫维护都不可行,怎么办?回到上面的思路,我们只计算儿子对自己的贡献可以做到 \(O(1)\) 修改。可是我们不能只看儿子贡献啊?每个点的父亲贡献不同,所以不能单纯用儿子贡献做关键字存 set。考虑到一个点的所有儿子的父亲贡献相等,则自然而然想到将该点的儿子们的信息维护在该点的 set 中。那么我们只需把该点的 set 的最大最小取出,加上该点对儿子的贡献丢进全局 set,就能做到 \(O(q\log n)\) 了。常数较大。

实现

注意到 \(n\) 比较小,时间充裕,我们以防万一,也为了代码简洁,维护最大最小值时,可以先把有关点的 set 中放入全局 set 中的元素删除,修改了该点的 set 后再取最大最小值放入全局 set 中。善于使用函数的话,可以写的比较简洁。

core code:

int n,m;
LL v[N+10],ic[N+10]; //value and income 权值与来自儿子的收益
int fa[N+10],sc[N+10]; //父亲与儿子数
multiset<LL> ch[N+10],mm; //每个点的儿子 set 与全局 set inline void Addm(int u){ //将点 u 的 set 取最大最小值加上 u 对其贡献放入全局 set 中
if(sc[u]){
mm.insert(*ch[u].begin()+v[u]/(sc[u]+2));
if(sc[u]>1)
mm.insert(*--ch[u].end()+v[u]/(sc[u]+2));
}
} inline void Delm(int u){ //同上函数,但是是删除
if(sc[u]){
mm.erase(mm.find(*ch[u].begin()+v[u]/(sc[u]+2)));
if(sc[u]>1)
mm.erase(mm.find(*--ch[u].end()+v[u]/(sc[u]+2)));
}
} inline void Change(int u,LL x){ //修改一个点的来自儿子的收益
int f=fa[u];
Delm(f);
ch[f].erase(ch[f].find(ic[u]));
ic[u]+=x;
ch[f].insert(ic[u]);
Addm(f);
} inline void Del(int u){ //断开 u 到父亲的边
int f=fa[u];
Delm(f);
ch[f].erase(ch[f].find(ic[u]));
Change(fa[f],v[f]/(sc[f]+1)-v[f]/(sc[f]+2));
Change(f,(sc[f]+1)*(v[f]/(sc[f]+2))-sc[f]*(v[f]/(sc[f]+1))-v[u]/(sc[u]+2));
--sc[f];
fa[u]=0;
Addm(f);
} inline void Link(int u,int f){ //连接 u 到 f 的边,内容与上函数类似,相反而已
Delm(f);
fa[u]=f;
++sc[f];
Change(f,v[u]/(sc[u]+2)-(sc[f]+1)*(v[f]/(sc[f]+2))+sc[f]*(v[f]/(sc[f]+1)));
Change(fa[f],v[f]/(sc[f]+2)-v[f]/(sc[f]+1));
ch[f].insert(ic[u]);
Addm(f);
} int main(){
n=Read(),m=Read();
for(int i=1;i<=n;++i)
v[i]=Read();
for(int i=1;i<=n;++i)
++sc[fa[i]=Read()];
for(int i=1;i<=n;++i)
ic[fa[i]]+=v[i]/(sc[i]+2),ic[i]+=v[i]-(sc[i]+1)*(v[i]/(sc[i]+2));
for(int i=1;i<=n;++i)
ch[fa[i]].insert(ic[i]);
for(int i=1;i<=n;++i)
Addm(i);
++m;
while(--m){
int op=Read();
if(op==1){
int x=Read(),y=Read();
Del(x);
Link(x,y);
}
else if(op==2){
int x=Read();
printf("%lld\n",ic[x]+v[fa[x]]/(sc[fa[x]]+2));
}
else
printf("%lld %lld\n",*mm.begin(),*--mm.end());
}
return 0;
}

最新文章

  1. wex5 实战 HeidiSQL 导入Excel数据
  2. hdu 5596 GTW likes gt
  3. 建立开发板与PC机之间的nfs服务器
  4. centos 防火墙设置
  5. dll强签名的由来和作用
  6. Java 正则表达式的总结和一些小例子
  7. 分布式应用处理方式 - Remoting
  8. 使用KVC
  9. 使用DOM进行xml文档的crud(增删改查)操作&lt;操作详解&gt;
  10. SQL Server 查看一个表上的索引
  11. maven的命令使用笔记
  12. 2.13.2. 对结果集进行筛选(Core Data 应用程序实践指南)
  13. log4go的全局封装Wrapper和标准log库函数的兼容
  14. 在ubantu上安装hive
  15. GCD之死锁体会
  16. Oracle数据库(3-7)
  17. windows下mongodb安装详解
  18. DSAPI Wifi热点的扫描与连接
  19. JsonRequestBehavior不存在问题,JsonRequestBehavior属于哪个dll
  20. iOS字符串自动计算文本的宽和高

热门文章

  1. 如何实现在react现有项目中嵌入Blazor?
  2. SOFAJRaft源码阅读-模块启动过程
  3. 工作这么多年,我总结的数据传输对象 (DTO) 的最佳实践
  4. Git分支变基-知识点整理记录
  5. java反序列化基础
  6. 线程基础知识 04 synchronized锁的四种状态和升级
  7. 懂九转大肠的微软New Bing 内测申请教程
  8. The Missing Semester - 第三讲 学习笔记
  9. 自动化测试方案对比:Katalon vs Python
  10. Spark系列 - (3) Spark SQL