[VK Cup 2016 - Round 3] - D Bearish Fanpages

洛谷传送门
Codeforces传送门

题目描述

There is a social website with n n n fanpages, numbered 1 1 1 through n n n . There are also n n n companies, and the i i i-th company owns the i i 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 i i follows j j j and at the same time j j j follows i i i . Also, a fanpage can’t follow itself.

Let’s say that fanpage i i i follows some other fanpage j 0 j_{0} j0 . Also, let’s say that i i i is followed by k k k other fanpages j 1 , j 2 , . . . , j k j_{1},j_{2},...,j_{k} j1,j2,...,jk . Then, when people visit fanpage i i i they see ads from k + 2 k+2 k+2 distinct companies: i , j 0 , j 1 , . . . , j k i,j_{0},j_{1},...,j_{k} i,j0,j1,...,jk . Exactly t i t_{i} ti people subscribe (like) the i i i -th fanpage, and each of them will click exactly one add. For each of k + 1 k+1 k+1 companies j 0 , j 1 , . . . , j k j_{0},j_{1},...,j_{k} j0,j1,...,jk, exactly img people will click their ad. Remaining img 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 i i follows fanpage f i f_{i} fi . Your task is to handle q q q queries of three types:

  • 1 i j — fanpage i i i follows fanpage j j j from now. It’s guaranteed that i i i didn’t follow j j 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 i 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 n n and q q q ( 3 ≤ n ≤ 100000 , 1 ≤ q ≤ 100000 ) ( 3\le n\le 100000 , 1\le q\le 100000 ) (3n100000,1q100000) — the number of fanpages and the number of queries, respectively.

The second line contains n n n integers t 1 , t 2 , . . . , t n t_{1},t_{2},...,t_{n} t1,t2,...,tn ( 1 ≤ t i ≤ 1 0 12 ) ( 1\le t_{i}\le10^{12} ) (1ti1012) where t i t_{i} ti denotes the number of people subscribing the i i i -th fanpage.

The third line contains n n n integers f 1 , f 2 , . . . , f n ( 1 ≤ f i ≤ n ) f_{1},f_{2},...,f_{n} ( 1\le f_{i}\le n ) f1,f2,...,fn(1fin). Initially, fanpage i i i follows fanpage f i f_{i} fi .

Then, q q q lines follow. The i i i -th of them describes the i i 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 50000 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

解题分析

一开始以为是什么牛逼的数据结构, 结果是个大暴力。

考虑对于每个点只维护其子节点和自己对自己的答案贡献为 a n s [ i ] ans[i] ans[i], 然后某个节点的答案就是父节点对自己的贡献加上维护的自己的这个值, 用个 s e t set set就可以从小到大按照 a n s [ i ] ans[i] ans[i]排序儿子节点了。 然后在外面用一个 m u l t i s e t multiset multiset存所有节点的子节点加上这个节点对它们的贡献的最大最小值(即真正的答案)。

然后修改的时候只会有 x x x f [ x ] f[x] f[x] f [ f [ x ] ] f[f[x]] f[f[x]] y y y f [ y ] f[y] f[y]的答案值可能改变, 单独拉出来它们及其父亲修改再塞回去就好了。

至于单独的一个查询, 直接输出 a n s [ i ] ans[i] ans[i] f [ i ] f[i] f[i] i 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);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值