Codeforces 1535E Gold Transfer(暴力,树上倍增)

3 篇文章 0 订阅
1 篇文章 0 订阅

题目链接:https://codeforces.com/problemset/problem/1535/E

Codeforces 1535E Gold Transfer

暴力,树上倍增
考虑到每个插入的子结点的c[i]>c[p[i]],所以要使得取的物品花费最小,一定是从根节点往下取。考虑每插入一个节点时维护它向上走的倍增数组f[i][j]表示从节点i往上走2j次后达到的节点编号。若需要查询节点v,则用倍增数组找到离他最远的a[i]不为0的祖先,因为取数一定是从根节点往下取,所以所有在这个祖先之上的节点的a[i]值一定为0,可以不用考虑。从这个祖先开始逐个节点往下取数,直到取到w个物品或者取到v节点时退出。因为取完的节点不用考虑,所以每个节点最多只会被取到一次,复杂度为O(qlogq)。

#include<bits/stdc++.h>
#define next next_
#define y1 yy
#define hash hash_
#define complex complex_
using namespace std;

using ll=long long;
using ull=unsigned long long;
using pii=pair<int,int>;
using pll=pair<ll,ll>;

const ll mod=1e9;
const double pi=acos(-1.0);
int _;

ll q,p,a[300010],c[300010],dep[300010];
ll f[300010][25];
ll v,w;

void work(){
	scanf("%lld%lld%lld",&q,&a[0],&c[0]);
	for(ll i=1,s;i<=q;i++){
		scanf("%lld",&s);
		if(s==1){
			scanf("%lld%lld%lld",&p,&a[i],&c[i]);
			f[i][0]=p;
			dep[i]=dep[p]+1;
			for(ll j=1;j<=20;j++) f[i][j]=f[f[i][j-1]][j-1];
		}
		else{
			ll ans1=0,ans2=0;
			scanf("%lld%lld",&v,&w);
			ll pos=v;
			for(ll j=20;j>=0;j--) if(a[f[pos][j]]) pos=f[pos][j];
			ll dis=dep[v]-dep[pos];
			while(1){
				pos=v;
				for(ll j=0;j<=20;j++) if((dis>>j)&1) pos=f[pos][j];
				ll sum=min(w,a[pos]);
				ans1+=sum;
				ans2+=sum*c[pos];
				w-=sum;
				a[pos]-=sum;
				if(!w||!dis) break;
				dis--;
			}
			printf("%lld %lld\n",ans1,ans2);
			fflush(stdout);
		}
	}
}

int main(){
//	scanf("%d",&_);
	_=1;
	while(_--){
		work();
	}
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值