题意

原意简述版

有 \(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;
}

题解[CF674D]Bearish_Fanpages的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. 2023牛客寒假算法基础集训营2 ABCDEFHJKL

    比赛链接 A 题解 知识点:数学. 用 \(n\) 减去区间1的端点得到匹配的一个区间,求一下与区间2的交集. 一个小公式,两区间 \([L_1,R_1]\) 和 \([L_2,R_2]\) 的交集长 ...

  2. python 第一二次教学笔记之数据操作

    对Python 有一个认知 记住这是一个动态类型的,弱类型语言 ds =111.0 #弱类型 前面不用写明是具体什么类型 haobo=10 haobo = ds #类型转换不再有高低之分 hoabo ...

  3. C#高性能数组拷贝实验

    前言 昨天 wc(Wyu_Cnk) 提了个问题 C# 里多维数组拷贝有没有什么比较优雅的写法? 这不是问对人了吗?正好我最近在搞图像处理,要和内存打交道,我一下就想到了在C#里面直接像C/C++一样做 ...

  4. 洛谷 P3137 [USACO16FEB]Circular Barn S

    题目链接 本蒟蒻的第一篇题解,写得不好请指出,敬请谅解 题意: 有\(n\)头奶牛,分布在一些房间,某些房间可能有多头牛,要让这些牛按顺时针移动,求使每一个房间刚好有一个奶牛的最小花费 花费计算:如果 ...

  5. 汉诺塔 Java && Cpp 实现

    不论多少盘,都看成是两个盘在移动,只需要把上面的两个盘移动好就行. public static void hanoiTower(int num,char a,char b ,char c) { if( ...

  6. 线程基础知识11-CAS+自旋锁

    1.CAS是什么(CompareAndSet) CAS(Compare and swap)比较和替换是设计并发算法时用到的一种技术.简单来说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果 ...

  7. Servlet HTTP Request Response笔记

    # 今日内容:    1. Servlet    2. HTTP协议    3. Request## Servlet:    1. 概念    2. 步骤    3. 执行原理    4. 生命周期  ...

  8. Java编译异常捕捉与上报笔记

    异常处理机制的作用:增强程序的健壮性 处理编译异常方式一: 在方法声明位置上使用throws关键字抛出,谁调用该方法,就交给谁处理 注意:为Exception的是需要处理的,否则编译器会报错,可以一直 ...

  9. 接入jira OAuth权限流程

    如果要在自己的系统中操作jira的api完成这些单据的创建.审批等操作,就不得不要先完成jira的第三方授权,才能在第三方系统去做这些jira的操作. 首先必须在jira系统配置客户端的相关信息,须配 ...

  10. FPS 逆向 CS.起源 绘制 教程(下周完成笔记)

    1.找到人物坐标X YZ2.找到鼠标X Y3.易语言读取人物坐标4.读取敌人坐标打开控制台服务器与客户端尽量找客户端 找到XYZ5.实时读取敌人坐标6.三角函数转换屏幕坐标FOV 视场角狙击枪找FOV ...