zoukankan      html  css  js  c++  java
  • 【GOJ 1489】Monster Hunter

    题目

    正解

    首先,这是一棵有根树,其次,很明显每只怪物都要父亲怪物被击杀后才可以被击杀,我们不妨想问题的时候从简单的出发,就是:假如没有父亲这个限制,我们应该怎样打怪物呢,首先我们可以把怪物分成两类: (a lt b)(a geq b)的,前面一类打完不会掉血,后面则会掉血,那么这时候肯定先把前面一类的打完之后再打第二类的是更加优的。

    • (a lt b)的怪物呢,我们也应该按照a从小到大的顺序打。

    • (a geq b)的怪物呢,考虑两只怪物的击杀顺序(i,j),那么有两种情况:先打(i)或者先打(j)

    • (i)(HP+min(-a[i],-a[i]+b[i]-a[j])), 因为(age b) ,所以有(HP-a[i]-a[j]+b[i])

      • 先打(j)同理有(HP-a[i]-a[j]+b[j]),可以发现 (HP-a[i]-a[j])是一样需要的,所以我们应该按照b的从大到小的顺序打。

    那么我们这样就可以在(O(1))的时间内比较出应该先打谁了,假设忽略了父亲限制之后的攻击顺序为(p_1,p_2,..,p_n)

    • (p_1=1),那么第一步打(p_1)一定是最优的。

    • (p_1!=1),那么在打完(p_1)的父亲(x)后,紧接着打(p_1)一定是最优的,直接把(p_1)(x)的两只怪物合并,依然用((a,b))表示,并且把(p_1)所有儿子的父亲改为(x)就可以消除(p_1)的影响了,么每次消除(1)个,算法复杂度为(o(n))

    很明显需要支持修改一个怪物,删除最优怪物,以为修改父亲的操作;那么找最优怪物,我们可以用优先队列,对于修改父亲,我们可以用并查集维护就ok,所以总的复杂度应该是(o(nlogn))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,j,k) for(int i=j;i<=k;++i)
    typedef long long ll;
    char cch;
    inline int rd(){
    	int x=0,fl=1;
    	cch=getchar();
    	while(cch>'9'||cch<'0'){
    		if(cch=='-') fl=-1;
    		cch=getchar();
    	}
    	while(cch>='0'&&cch<='9') x=(x<<3)+(x<<1)+cch-'0',cch=getchar();
    	return x*fl;
    }
    const int N=1e5+3;
    struct abc{
    	int i;
    	ll a,b;
    	bool operator <(const abc & x)const{
    		int sn1=a<b,sn2=x.a<x.b;
    		if(sn1<sn2) return true;
    		if(sn1==sn2){
    			if(a<b) return a>x.a;
    			return b<x.b;
    		}
    		return 0;
    	}
    }a[N];
    bool vis[N];
    int to[N<<1],cnt,nxt[N<<1],fa[N],head[N];
    inline void adde(int u,int v){
    	to[++cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
    	to[++cnt]=u,nxt[cnt]=head[v],head[v]=cnt;
    }
    inline void dfs(int x,int f){
    	fa[x]=f;
    	for(int i=head[x];i;i=nxt[i]) if(to[i]!=f){
    		dfs(to[i],x);
    	}
    }
    inline int getfa(int x){
    	if(!fa[x]||!vis[x]) return x;
    	return fa[x]=getfa(fa[x]);
    }
    priority_queue<abc> q;
    int main(){//问题相当于求:Hp初始为0,可以随时购买,最少需要买多少Hp 
    	int n=rd(),u,v;
    	abc t;
    	rep(i,2,n) a[i].a=rd(),a[i].b=rd(),a[i].i=i,q.push(a[i]);
    	rep(i,2,n) u=rd(),v=rd(),adde(u,v);
    	dfs(1,0);
    	ll tmp;
    	while(!q.empty()){
    		t=q.top();q.pop();
    		u=t.i;
    		if(vis[u]||((t.a!=a[u].a)||(t.b!=a[u].b))) continue;
    		vis[u]=1;
    		v=getfa(u);
    		tmp=max(a[v].a,a[u].a+a[v].a-a[v].b);//购买需要的 Hp 
    		a[v].b=a[u].b+a[v].b-a[u].a-a[v].a+tmp;//总受益,加上tmp是因为 你为了Hp始终>=0购买了tmp的Hp,所以相当于凭空获得tmp 
    		a[v].a=tmp;
    		/*if(v>1)*/ q.push(a[v]);
    	}
    	printf("%lld",a[1].a); 
    }
    

    来源

    知识共享许可协议

    本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

    限于本人水平,如果文章有表述不当之处,还请不吝赐教。

  • 相关阅读:
    (二十)WebGIS中图层树功能的设计和实现
    WebGIS中矢量切图的初步研究
    百度兴趣点下载工具设计和实现
    服务端常规知识详解
    Shp数据批量导入Postgresql工具的原理和设计
    浅谈C#中一种类插件系统编写的简单方法(插件间、插件宿主间本身不需要通信)
    从底层开发谈WebGIS中实现地理长度固定的可视窗口的思路和方法
    用存储过程判断某个人员在一天的行进轨迹中是否有超过指定时间的停留
    Linux启动与禁止SSH用户及IP的登录
    JVM中的垃圾回收
  • 原文地址:https://www.cnblogs.com/Sam2007/p/13121724.html
Copyright © 2011-2022 走看看