CF643D Bearish Fanpages 题解
题意
- 给定一个 个点的基环森林,第 个点与 之间有一条边。
- 保证在任意时刻,这个基环森林中的环长至少为 。
- 当一种「神秘事件」发生时,对于第 个点,设与其相邻的点(包括 和 的 )的个数为 ,这 个点上都会出现 个人,而 上会出现 个人。
- 每次「神秘事件」发生都是互不影响的。
- 有 个操作,操作有三种。
1 i j:将 改为 ,此操作不超过 个。2 i:询问当「神秘事件」发生时,第 个点上出现的人数。3:询问当「神秘事件」发生时,所有点上出现的人数的最小值和最大值。
- ,。
题解
对于点 ,将 的所有 的权值去掉 的贡献后存到 上的一个 multiset 里(记为 ),然后 multiset 里的最大最小值加上 的贡献存到一个大 multiset 里(记为 )。
设 表示 去掉 的贡献后的权值, 表示 的度数。
考虑每次修改,即将 改为 的过程:
- 由于修改后 不再对 有贡献, 要减去修改前来自 的贡献 , 中删除 。
- 由于 修改后要减去 , 要减去修改前自身的贡献 ,加上修改后自身的贡献 , 要更新 。
- 由于 修改后要减去 , 要减去修改前来自 的贡献 ,加上修改后来自 的贡献 , 要更新 。
此时执行修改,即 减去 , 改为 , 加上 ,然后将上面的过程反向重复一遍。
- 由于修改前 对 没有贡献, 要加上修改后来自 的贡献 , 中插入 。
- 由于 修改后加上了 , 要减去修改前自身的贡献 ,加上修改后自身的贡献 , 要更新 。
- 由于 修改后加上了 , 要减去修改前来自 的贡献 ,加上修改后来自 的贡献 , 要更新 。
注意每次更新 的操作实质上是先删除再修改后插入,必须保证删除在修改之前,因此不能完全按照上面的顺序来做。
另外,别忘了每次更新 还要同步更新 ,同时注意不能重复插入或删除。
所以实际上本题是个模拟题,总时间复杂度 。
代码
const int N = 1e5 + 7;
int n, q, d[N], f[N];
bool v[N];
ll a[N], t[N];
multiset<ll> s[N];
inline void del(int x) {
if (v[x] && s[x].size())
v[x] = 0,
s[0].erase(s[0].find((*s[x].begin()) + t[x] / (d[x] + 1))),
s[0].erase(s[0].find((*(--s[x].end())) + t[x] / (d[x] + 1)));
}
inline void add(int x) {
if (!v[x] && s[x].size())
v[x] = 1,
s[0].insert((*s[x].begin()) + t[x] / (d[x] + 1)),
s[0].insert((*(--s[x].end())) + t[x] / (d[x] + 1));
}
inline void work(int i, int j) {
del(f[i]), del(f[f[i]]), del(f[f[f[i]]]);
del(j), del(f[j]), del(f[f[j]]);
s[f[i]].erase(s[f[i]].find(a[i]));
s[f[f[i]]].erase(s[f[f[i]]].find(a[f[i]]));
a[f[i]] -= t[i] / (d[i] + 1);
a[f[i]] -= t[f[i]] - d[f[i]] * (t[f[i]] / (d[f[i]] + 1));
a[f[i]] += t[f[i]] - (d[f[i]] - 1) * (t[f[i]] / d[f[i]]);
s[f[f[i]]].insert(a[f[i]]);
s[f[f[f[i]]]].erase(s[f[f[f[i]]]].find(a[f[f[i]]]));
a[f[f[i]]] -= t[f[i]] / (d[f[i]] + 1);
a[f[f[i]]] += t[f[i]] / d[f[i]];
s[f[f[f[i]]]].insert(a[f[f[i]]]);
--d[f[i]], ++d[j];
s[j].insert(a[i]);
s[f[j]].erase(s[f[j]].find(a[j]));
a[j] += t[i] / (d[i] + 1);
a[j] -= t[j] - (d[j] - 1) * (t[j] / d[j]);
a[j] += t[j] - d[j] * (t[j] / (d[j] + 1));
s[f[j]].insert(a[j]);
s[f[f[j]]].erase(s[f[f[j]]].find(a[f[j]]));
a[f[j]] -= t[j] / d[j];
a[f[j]] += t[j] / (d[j] + 1);
s[f[f[j]]].insert(a[f[j]]);
add(f[i]), add(f[f[i]]), add(f[f[f[i]]]);
add(j), add(f[j]), add(f[f[j]]);
f[i] = j;
}
int main() {
rd(n), rd(q), rda(t, n), rda(f, n);
for (int i = 1; i <= n; i++) ++d[i], ++d[f[i]];
for (int i = 1; i <= n; i++)
a[i] += t[i] - d[i] * (t[i] / (d[i] + 1)),
a[f[i]] += t[i] / (d[i] + 1);
for (int i = 1; i <= n; i++) s[f[i]].insert(a[i]);
for (int i = 1; i <= n; i++) add(i);
while (q--) {
int o, i, j;
rd(o);
switch (o) {
case 1 : rd(i), rd(j), work(i, j); break;
case 2 : rd(i), print(a[i] + t[f[i]] / (d[f[i]] + 1)); break;
case 3 : print(*s[0].begin(), ' '), print(*(--s[0].end())); break;
}
}
return 0;
}
评论
暂无已公开评论。