[hdu6326]Monster Hunter

关于打怪兽的顺序,有经典结论:

优先打$a<b$的怪兽,这些怪兽按$a$从小到大,其余怪兽按$b$从大到小

(证明调整法即可,具体略)

在此基础上,类似[AGC023F]01 on Tree,同样不断将最优的怪物与父亲合并即可(合并后仍可以用"怪兽"描述)

时间复杂度为$o(n\log n)$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define ll long long
 5 struct Data{
 6     ll a,b;
 7     bool operator < (const Data &k)const{
 8         if ((a<=b)!=(k.a<=k.b))return a<=b;
 9         if (a<=b)return a<k.a;
10         return b>k.b;
11     }
12 }a[N];
13 vector<int>v[N];
14 set<pair<Data,int> >S;
15 int t,n,x,y,fa[N],f[N];
16 Data merge(Data x,Data y){
17     ll a=max(x.a,x.a-x.b+y.a);
18     return Data{a,x.b+y.b-x.a-y.a+a};
19 }
20 int find(int k){
21     if (k==f[k])return k;
22     return f[k]=find(f[k]);
23 }
24 void dfs(int k,int f){
25     fa[k]=f;
26     for(int i=0;i<v[k].size();i++)
27         if (v[k][i]!=f)dfs(v[k][i],k);
28 }
29 void merge(int x,int y){
30     x=find(x),y=find(y);
31     if (x!=1)S.erase(make_pair(a[x],x));
32     f[y]=x,a[x]=merge(a[x],a[y]);
33     if (x!=1)S.insert(make_pair(a[x],x));
34 }
35 int main(){
36     scanf("%d",&t);
37     while (t--){
38         scanf("%d",&n);
39         a[1]=Data{0,0},S.clear();
40         for(int i=1;i<=n;i++)v[i].clear();
41         for(int i=2;i<=n;i++){
42             scanf("%lld%lld",&a[i].a,&a[i].b);
43             S.insert(make_pair(a[i],i));
44         }
45         for(int i=1;i<n;i++){
46             scanf("%d%d",&x,&y);
47             v[x].push_back(y);
48             v[y].push_back(x);
49         }
50         dfs(1,0);
51         for(int i=1;i<=n;i++)f[i]=i;
52         for(int i=1;i<n;i++){
53             int x=(*S.begin()).second;
54             S.erase(S.begin());
55             merge(fa[x],x);
56         }
57         printf("%lld\n",a[1].a);
58     }
59     return 0;
60 }
View Code

 

posted @ 2022-06-25 16:04  PYWBKTDA  阅读(134)  评论(0编辑  收藏  举报