G - Game HDU - 5242 (数链剖分)
题目链接:
G - Game
题目大意:首先是T组测试样例,给出一颗以1节点为根的树,每个节点有各自的价值,有m次从根节点出发向下走到叶子节点的机会,每次会得到所有经过节点的权值,每个节点只有在第一次经过时有价值,求m次之后能够获得的最大权值。
具体思路:数链剖分,把重链按照权值划分,当前链储存的是这条链上的总的权值。
AC代码:
1 #include<iostream>
2 #include<stdio.h>
3 #include<cmath>
4 #include<string>
5 #include<algorithm>
6 using namespace std;
7 # define ll long long
8 # define inf 0x3f3f3f3f
9 const int maxn = 2e5+100;
10 const int mod = 1e9;
11 ll val[maxn];
12 int edgenum,dfsnum,depth[maxn];
13 int son[maxn],father[maxn],ord[maxn];
14 ll Size[maxn];
15 int top[maxn];
16 vector<int>Edge[maxn];
17 vector<ll>sto;
18 void init()
19 {
20 edgenum=0;
21 dfsnum=0;
22 }
23 void dfs1(int fr,int rt,int dep)
24 {
25 father[fr]=rt;
26 Size[fr]=0;
27 son[fr]=-1;
28 depth[fr]=dep;
29 for(int i=0; i<Edge[fr].size(); i++)
30 {
31 int to=Edge[fr][i];
32 if(to==rt)continue;
33 dfs1(to,fr,dep+1);
34 Size[fr]=max(Size[fr],Size[to]);
35 if(son[fr]==-1||(Size[son[fr]]<Size[to]))
36 {
37 son[fr]=to;
38 }
39 }
40 Size[fr]+=val[fr];// 可以手动模拟一遍dfs的过程就能明白了
41 }
42 void dfs2(int fr,int rt)
43 {
44 ord[fr]=++dfsnum;
45 top[fr]=rt;
46 if(son[fr]!=-1)
47 dfs2(son[fr],rt);
48 for(int i=0; i<Edge[fr].size(); i++)
49 {
50 int to=Edge[fr][i];
51 if(son[fr]!=to&&father[fr]!=to)
52 {
53 dfs2(to,to);
54 }
55 }
56 }
57 int main()
58 {
59 int T,Case=0;
60 scanf("%d",&T);
61 while(T--)
62 {
63 dfsnum=0;
64 int n,k;
65 scanf("%d %d",&n,&k);
66 for(int i=1; i<=n; i++)
67 {
68 scanf("%d",&val[i]);
69 Edge[i].clear();
70 }
71 int st,ed;
72 for(int i=1; i<n; i++)
73 {
74 scanf("%d %d",&st,&ed);
75 Edge[st].push_back(ed);
76 // Edge[ed].push_back(st);
77 }
78 dfs1(1,-1,1);
79 dfs2(1,1);
80 sto.clear();
81 for(int i=1; i<=n; i++)
82 {
83 if(top[i]!=i)
84 continue;
85 ll sum=0,pos=i;
86 while(pos!=-1)
87 {
88 sum+=(ll)val[pos];
89 pos=son[pos];
90 }
91 sto.push_back(sum);
92 }
93 sort(sto.begin(),sto.end());
94 ll sum=0;
95 int len=sto.size();
96 for(int i=len-1; i>=max(0,len-k); i--)
97 {
98 sum+=sto[i];
99 }
100 printf("Case #%d: %lld\n",++Case,sum);
101 }
102 return 0;
103 }