洛谷传送门
Codeforces传送门
题目描述
There is a social website with n fanpages, numbered 1 through n . There are also n companies, and the i-th company owns the i -th fanpage.
Recently, the website created a feature called following. Each fanpage must choose exactly one other fanpage to follow.
The website doesn’t allow a situation where i follows j and at the same time j follows i . Also, a fanpage can’t follow itself.
Let’s say that fanpage i follows some other fanpage j0 . Also, let’s say that i is followed by k other fanpages j1,j2,...,jk . Then, when people visit fanpage i they see ads from k+2 distinct companies: i,j0,j1,...,jk . Exactly ti people subscribe (like) the i -th fanpage, and each of them will click exactly one add. For each of k+1 companies j0,j1,...,jk, exactly people will click their ad. Remaining people will click an ad from company ii (the owner of the fanpage).
The total income of the company is equal to the number of people who click ads from this copmany.
Limak and Radewoosh ask you for help. Initially, fanpage i follows fanpage fi . Your task is to handle q queries of three types:
-
1 i j
— fanpage i follows fanpage j from now. It’s guaranteed that i didn’t follow j just before the query. Note an extra constraint for the number of queries of this type (below, in the Input section). -
2 i
— print the total income of the i -th company. -
3
— print two integers: the smallest income of one company and the biggest income of one company.
输入输出格式
输入格式:
The first line of the input contains two integers n and q (3≤n≤100000,1≤q≤100000) — the number of fanpages and the number of queries, respectively.
The second line contains n integers t1,t2,...,tn (1≤ti≤1012) where ti denotes the number of people subscribing the i -th fanpage.
The third line contains n integers f1,f2,...,fn(1≤fi≤n). Initially, fanpage i follows fanpage fi .
Then, q lines follow. The i -th of them describes the i -th query. The first number in the line is an integer $type_{i} ( 1\le type_{i}\le 3 ) $— the type of the query.
There will be at most 50000 queries of the first type. There will be at least one query of the second or the third type (so, the output won’t be empty).
It’s guaranteed that at each moment a fanpage doesn’t follow itself, and that no two fanpages follow each other.
输出格式:
For each query of the second type print one integer in a separate line - the total income of the given company. For each query of the third type print two integers in a separate line - the minimum and the maximum total income, respectively.
输入输出样例
输入样例#1:
5 12
10 20 30 40 50
2 3 4 5 2
2 1
2 2
2 3
2 4
2 5
1 4 2
2 1
2 2
2 3
2 4
2 5
3
输出样例#1:
10
36
28
40
36
9
57
27
28
29
9 57
解题分析
一开始以为是什么牛逼的数据结构, 结果是个大暴力。
考虑对于每个点只维护其子节点和自己对自己的答案贡献为ans[i], 然后某个节点的答案就是父节点对自己的贡献加上维护的自己的这个值, 用个set就可以从小到大按照ans[i]排序儿子节点了。 然后在外面用一个multiset存所有节点的子节点加上这个节点对它们的贡献的最大最小值(即真正的答案)。
然后修改的时候只会有x, f[x],f[f[x]], y, f[y]的答案值可能改变, 单独拉出来它们及其父亲修改再塞回去就好了。
至于单独的一个查询, 直接输出ans[i]和f[i]对i的贡献。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <set>
#include <vector>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MX 100500
#define gc getchar()
#define ll long long
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
ll ans[MX], val[MX];
int n, q;
std::multiset <ll> Ans;
struct Comp
{
IN bool operator () (const int &x, const int &y)
{return ans[x] == ans[y] ? x < y : ans[x] < ans[y];}
};
struct Node
{
std::set <int , Comp> st;
int deg, fat;
IN std::vector <int> get()//max and min
{
std::vector <int> ret;
if (!st.empty())
ret.push_back(*st.begin());
if (st.size() > 1)
{
auto i = st.end(); i--;
ret.push_back(*i);
}
return ret;
}
}dat[MX];
IN ll other(R int x) {return val[x] / (dat[x].deg + 2);}//contribution to other points
IN ll self(R int x) {return val[x] - (dat[x].deg + 1) * other(x);}
int main(void)
{
int typ, foo, bar;
in(n), in(q);
std::vector <int> res;
for (R int i = 1; i <= n; ++i) in(val[i]);
for (R int i = 1; i <= n; ++i)
{
in(dat[i].fat);
++dat[dat[i].fat].deg;
dat[dat[i].fat].st.insert(i);
}
for (R int i = 1; i <= n; ++i)
{
dat[dat[i].fat].st.erase(i);
ans[i] = self(i);
for (auto j : dat[i].st) ans[i] += other(j);
dat[dat[i].fat].st.insert(i);
}
for (R int i = 1; i <= n; ++i)
{
res = dat[i].get();
for (auto j : res) Ans.insert(other(i) + ans[j]);
}
W (q--)
{
in(typ);
if (typ == 1)
{
in(foo), in(bar);
std::set <int> base = {foo, dat[foo].fat, dat[dat[foo].fat].fat, bar, dat[bar].fat};
std::set <int> upd = base;
for (auto i : base) upd.insert(dat[i].fat);
for (auto i : upd)
{
res = dat[i].get();
for (auto j : res) Ans.erase(Ans.find(other(i) + ans[j]));
}
for (auto i : base) dat[dat[i].fat].st.erase(i);
for (R int tp = -1; tp <= 1; tp += 2)
{
for (auto i : base)
{
ans[i] += tp * self(i);
for (auto j : base) if (i == dat[j].fat)
ans[i] += tp * other(j);
}
if (tp == -1)
--dat[dat[foo].fat].deg, ++dat[bar].deg, dat[foo].fat = bar;
}
for (auto i : base) dat[dat[i].fat].st.insert(i);
for (auto i : upd)
{
res = dat[i].get();
for (auto j : res) Ans.insert(ans[j] + other(i));
}
}
else if (typ == 2) in(foo), printf("%I64d\n", ans[foo] + other(dat[foo].fat));
else
{
printf("%I64d ", *Ans.begin());
auto i = Ans.end(); i--;
printf("%I64d\n", *i);
}
}
}