DTOJ#5152. 数据恢复

题目背景

宫水三叶被要求出一场测试,于是三叶非常认真的出了一套题。

然而在临近测试时,一场意外使得这场测试所有的资料全部被清空了。其中包括题面,题解,标程和数据。

无奈之下,三叶找到了小H,希望她能恢复这些被清空的数据。

题目描述

擅长电脑的小H明白,这些数据是可恢复的,所以小H决定帮助三叶。

由于某些原因,这些数据有依赖关系,复原一个数据需要复原它所依赖的数据。这些依赖关系形成一棵树。

对于一个数据,假设它有两个系数 a i , b i a_i,b_i ai,bi ,在复原这个数据时,因为还要保证没有被复原的数据的完整性,需要的代价为:

b i ⋅ ∑ j 还没被复原 a j b_i\cdot \sum_{j \text{还没被复原}} a_j bij还没被复原aj

H认为自己一定可以在规定时间内复原出数据,但是她想捉弄一下三叶。因此小H想要让复原的时间尽可能,也就是让上述代价尽量大

现在你知道 n n n 个数据的系数和它们之间的依赖关系,请求出最大代价。

形式化题意

给定一棵 n n n 个点的树,对于所有 2 ≤ i ≤ n 2\le i \le n 2in ,它的父亲节点为 f i f_i fi ,每一个点有两个系数 a i , b i a_i,b_i ai,bi

你需要求出一个长度为 n n n 的排列,满足对于 2 ≤ i ≤ n 2\le i \le n 2in f i f_i fi 都在 i i i 出现前出现。

这个排列的代价为:

∑ i = 1 n ( b p i ∑ j = i + 1 n a p j ) \sum_{i=1}^{n}(b_{p_i}\sum_{j=i+1}^{n}a_{p_j}) i=1n(bpij=i+1napj)

求最大代价。

第一行一个整数 n n n ,表示需要复原的数据的个数。

第二行 n − 1 n-1 n1 个整数,第 i i i 个数表示 f i + 1 f_{i+1} fi+1 ,即复原第 i + 1 i+1 i+1 个数据需要先复原第 f i + 1 f_{i+1} fi+1 个数据。

接下来 n n n 行,每行两个整数 a i , b i a_i,b_i ai,bi ,表示第 i i i 个数据自身的两个系数。

输出一行,表示最大的代价。

样例输入 1
4
1 1 2
0 0
3 1
5 1
4 1
样例输出 1
14
样例解释 1

可以按照 1 , 2 , 4 , 3 1,2,4,3 1,2,4,3 的方式选择。

样例数据 2,3,4

见下发文件。

本题采用捆绑测试。

对于所有数据,满足 1 ≤ n ≤ 3 × 1 0 5 , 1 ≤ a i , b i ≤ 5000 , 1 ≤ f i < i 1 \le n \le 3\times 10^5,1 \le a_i,b_i \le 5000,1 \le f_i < i 1n3×105,1ai,bi5000,1fi<i

特殊说明:样例数据 1 , 2 1,2 1,2 中出现了 a 1 = b 1 = 0 a_1=b_1=0 a1=b1=0 的情况,但是数据不会出现此情况。

子任务见下表:

子任务编号 n n n特殊性质分值
1 1 1 ≤ 20 \le 20 20 − - 15 15 15
2 2 2 ≤ 1000 \le 1000 1000 − - 15 15 15
3 3 3 ≤ 5 × 1 0 4 \le 5\times 10^4 5×104 − - 15 15 15
4 4 4 ≤ 3 × 1 0 5 \le 3\times 10^5 3×105 f i = i − 1 f_i=i-1 fi=i1 10 10 10
5 5 5 ≤ 3 × 1 0 5 \le 3\times 10^5 3×105 f i = 1 f_i=1 fi=1 15 15 15
6 6 6 ≤ 3 × 1 0 5 \le 3\times 10^5 3×105 − - 30 30 30
后记

自信的小H最后并没有恢复所有被清除的数据,因此这场模拟赛原本的T1丢失了,然后有了你们现在看到的这道题。

这道题其实和蓝书上的染色几乎一样,都是倒序操作。
当存在依赖时,即操作必须存在先后,此时考虑如果不存在依赖,则按照 a i b i \frac{a_i}{b_i} biai递减选择。
又因为有依赖,所以必须在父亲后,即把点和父亲合并成新点,继续贪心。

#include<bits/stdc++.h>
#define N 300005
typedef long long ll;
using namespace std;
inline ll read(){
	ll x=0;char s=getchar();
	while(s<'0'||s>'9')s=getchar();
	while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	return x;
}
int fi[N],fa[N];
inline int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
struct node{
	ll sa,sb;
	int id,sz;
	inline node(int i=0,ll j=0,ll k=0,int h=0){
		id=i,sa=j,sb=k,sz=h;
	}
	bool operator<(const node &x)const{
		return sb*x.sa<x.sb*sa;
	}
};
priority_queue<node> q;
ll ans;
int sz[N];
ll sa[N],sb[N];
int main(){
//	freopen("data3.in","r",stdin);
  // freopen("data.in","r",stdin);
   // freopen("data.out","w",stdout);
	int n=read();ll suma=0,sumb=0;
	for(int i=1;i<=n;++i)fa[i]=i,sz[i]=1;
	for(int i=2;i<=n;++i){
		fi[i]=read();
	}
	for(int i=1;i<=n;++i){
		ll a=read(),b=read();sa[i]=a,sb[i]=b;
		suma+=a,sumb+=b;
		if(i>1)q.push(node(i,a,b,sz[i]));
	}
	
//	cout<<suma<<" "<<sumb<<endl;
	while(!q.empty()){
		node x=q.top();q.pop();
		if(x.sz!=sz[x.id])continue;
		int fx=get(fi[x.id]),px=get(x.id);
		if(fx==px)continue;
		//cout<<px<<endl;
		ans+=sb[fx]*sa[px];//printf("%lld %lld\n",sb[fx],sa[px]);
		sb[fx]+=sb[px],sa[fx]+=sa[px],sz[fx]+=sz[px];
		fa[px]=fx;
		if(fx!=1)q.push(node(fx,sa[fx],sb[fx],sz[fx]));
	}
	printf("%lld\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值