E2. Weights Division (hard version)

思路:
尽量一步一步的走,若一步无法得出结果,在p1堆顶和第二堆顶的位置cost总和小于p2最大的cost时,选择p2堆顶的值。
题解:

#E2. Weights Division (hard version)
#wrtier: qiurun
#time: 2020/8/21
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fi first
int t,n;
typedef long long ll;
ll sum = 0,S;
const int N = 1e5+5;
vector<pair<int,pair<int,int> > > g[N];
struct pp{
    
    
	ll w;
	ll cnt;
	ll cost;
	pp(ll _w,ll _cnt):w(_w),cnt(_cnt){
    
    
		cost = (w - w / 2) *cnt;
	}
	bool operator<(const pp& x)const{
    
    
	 	return cost < x.cost;
	}
};
priority_queue<pp> q1,q2;
ll dfs(int x,int pre){
    
    
	ll s = 0;
	if(x != 1 && g[x].size() == 1){
    
    	
		return 1;
	}
	for(int i = 0;i<g[x].size();i++){
    
    
		pair<int,pair<int,int> > p = g[x][i];
		int v = p.fi,w = p.se.fi,c = p.se.se;
		if(v == pre)
			continue;
		ll ts = dfs(v,x);
		sum += (ll)w * ts;
		if(c == 1)
			q1.push(pp(w,ts));
		else 
			q2.push(pp(w,ts));
		s += ts; 
	}
	return s;
}

int main(){
    
    
	int t;
	scanf("%d",&t);
	for(int i = 1;i <= t;i++){
    
    
		sum = 0;
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		scanf("%d%lld",&n,&S);
	
		for(int j = 1;j <= n;j++)
			g[j].clear();
		for(int j = 1;j <= n-1;j++){
    
    
			int u,v,w,c;
			scanf("%d%d%d%d",&u,&v,&w,&c);
			g[u].pb(mp(v,mp(w,c)));
			g[v].pb(mp(u,mp(w,c)));

		}
		dfs(1,-1);
		ll cst = 0;
		int flag = 0;
		while(sum>S){
    
    
			if (flag)break;
			if(q1.empty()){
    
    
				cst += 2;
				pp x = q2.top();
				q2.pop();
				sum -= x.cost;
				q2.push(pp(x.w/2,x.cnt));
			}else if(q2.empty()){
    
    
				cst ++;
				pp x = q1.top();
				q1.pop();
				sum -= x.cost;
				q1.push(pp(x.w/2,x.cnt));
			}
			else if(sum - q1.top().cost <= S){
    
    
				cst ++;
				sum = sum - q1.top().cost;
				flag = 1;
				break;
			}else if(sum - q2.top().cost <= S){
    
    
				cst+=2;
				sum = sum - q2.top().cost;
				flag =1;
				break;
			}else{
    
    
				pp x1 = q1.top(), x2(x1.w/2,x1.cnt);
				q1.pop();
				bool flag = 1;
				if(!q1.empty() && q1.top().cost > x2.cost){
    
    
				//在这里wa了很多发,因为没有计算第一个折半后和第二个的cost谁比较大
					x2 = q1.top();
					q1.pop();
				}else{
    
    
					flag = 0;
					x2= pp(x1.w/2,x1.cnt);
				}
				if(x1.cost + x2.cost >= q2.top().cost){
    
    
					cst += 1;
					sum = sum - x1.cost;
					q1.push(pp(x1.w/2,x1.cnt));
					if(flag)q1.push(x2);
				}else{
    
    
					q1.push(x1);
					if(flag)q1.push(x2);
					cst += 2;
					pp x = q2.top();
					q2.pop();
					sum -= x.cost;
					q2.push(pp(x.w/2,x.cnt));
				}
			}
		}
	printf("%lld\n",cst);
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_20252251/article/details/108151752