第十一届中国大学生程序设计竞赛网络预选赛 魔塔

这个战斗的情况非常的不正常,如果怪物不能破防还会给你加血。

于是我们可以和怪物战斗 \(\lceil\frac{h_i}{X-d_i}\rceil\) 回合,假设现在的防御力为 \(Y\),那么收益就是:

\[\lfloor\frac{h_i}{X-d_i}\rceil\times (Y-a_i) \]

对于每一个怪物,我们即 \(c_i=\lceil\frac{h_i}{X-d_i}\rceil\),那么显然 \(-c_i\times a_i\) 是肯定会造成的,我们只需要最大化 \(Y\times c_i\) 就行了。

这个问题可以加强成为下面的问题,最大化下式:

\[\sum\limits_{i<j} a_i\times b_j \]

其中 \((a_i,b_i)\) 表示第 \(i\) 个点可以增加多少防御力,\(b_i\) 表示这个节点的回合数。

考虑如果 \(a_i\times b_j>a_j\times b_i\),那么需要满足 \(\frac{a_i}{b_i}>\frac{a_j}{b_j}\),于是我们把这个东西作为关键在,排序之后计算肯定是最优的。

显然这是一个全序问题,考虑在放到树上之后怎么做。

其实是经典贪心,类似于 https://vjudge.net/problem/HDU-6326

感性理解,如果某个父亲如果没有其儿子优,那么我们取选择父亲肯定是为了选择儿子,于是我们直接把父亲和儿子绑定到一起,让父亲选完放上就拿儿子。

考虑通过调整法证明其正确性,我们假设存在一个父亲 \(fa\) 在没有儿子 \(x\) 优的情况下,没有马上选择 \(x\) 而是又去选择了另外一个节点 \(p\)

如果 \(p\)\(x\) 优,那么我们先选择 \(p\) 再选择 \(fa\) 一定更优。

如果 \(p\)\(fa\) 裂,那么最后选择 \(p\) 是更优的。

如果 \(p\)\(x\)\(fa\) 之间,那么其可能先于 \(fa\) 选择或者后于 \(p\),因为这至少可以造成 \(1\) 的贡献,而在中间选择什么都得不到。

我们这样操作是不会影响其他元素的,我们这些操作只会涉及 \(fa,p\) 的这个区间的选择进行交换,并不会把其他的元素交换进来。

于是就赢了,时间复杂度为 \(O(n\log n)\)

#include<iostream>
#include<queue>
#include<vector>
#include<bitset>
#define int long long
using namespace std;
const int N=1e5+5,inf=1e18;
int n,A,F[N],a[N],b[N],ans,p;
vector<int> v[N];
bitset<N> vis;
struct node{
	int a,b,id;
	friend bool operator <(const node a,const node &b){
		if (a.a*b.b!=a.b*b.a) return a.a*b.b<a.b*b.a;
		return a.a+inf*(!a.a&&!a.b)<b.b+inf*(!b.a&&!b.b);
	}
};
struct DSU{
	int fa[N];DSU(){for(int i=1;i<N;i++)fa[i]=i;}
	int f(int x){return fa[x]=(fa[x]==x?x:f(fa[x]));}
	void merge(int x,int y){fa[f(x)]=f(y);}
}dsu;
void dfs(int x,int f){
	F[x]=f;
	for(int i:v[x]) if(i!=f) dfs(i,x);
}
priority_queue<node>q;
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cin>>n>>A;
	for(int i=1,x,y;i<n;i++){
		cin>>x>>y;
		v[x].push_back(y);
		v[y].push_back(x);
	}
	dfs(1,0);
	for(int i=2,op,x,d,h;i<=n;i++){
		cin>>op;
		if(op==1){
			a[i]=1;
		}
		else{
			cin>>x>>d>>h,d=A-d;
			int t=(h+d-1)/d-1;
			ans-=t*x,b[i]=t;
		}
	}
	for(int i=1;i<=n;i++){
		q.push({a[i],b[i],i});
	}
	while(!q.empty()){
		auto [x,y,o]=q.top();q.pop();
		if(!vis[o]&&x==a[o]&&y==b[o]){
			p=dsu.f(F[o]),vis[o]=1,dsu.merge(o,F[o]);
			ans+=a[p]*y,a[p]+=x,b[p]+=y;
			if(p>1) q.push({a[p],b[p],p});
		}
	}
	cout<<ans<<'\n';
	return 0;
}
posted @ 2025-10-06 09:37  未抑郁的刘大狗  阅读(1)  评论(0)    收藏  举报