icpc上的题:12669
题解:我的题解是按照叶子链重小到大删叶子链,直到叶子链个数不大于k,每次删叶子链时记录删的节点权值和并且把答案减去这些删的权值和,最后还剩下的ans就是答案
不过这个题输入的是无向边,所以你得重新建树
问题 I: Happy Tree Friends
时间限制: 1 Sec 内存限制: 128 MB提交: 41 解决: 14
[提交] [状态] [命题人:admin]
题目描述
There is a Happy Tree on an island. Happy Tree consists of n apples linked by n-1 branches and the No.1 apple is the root of the tree. Each apple has a value a_i.
Today, k friends are playing under Happy Tree. Each of them can select only one apple, then gets the sum of the values from root to the selected apple, and take all the apples on the road (including the root and the selected apple). Of course, an apple can only be taken once.
Now, they want to know the maximum value they can get. They promise that everyone can select at least one apple.
Today, k friends are playing under Happy Tree. Each of them can select only one apple, then gets the sum of the values from root to the selected apple, and take all the apples on the road (including the root and the selected apple). Of course, an apple can only be taken once.
Now, they want to know the maximum value they can get. They promise that everyone can select at least one apple.
输入
The first line consists of two non-negative integers, the number of apples n, and the number of friends k. ( 1 ≤ n ,k ≤2×105 )
The second line consists of n non-negative integers, the value of the i-th apple a_i. ( 1 ≤ a_i ≤ 109 )
Then there are n-1 lines, each line consists of two non-negative integers, and describe a branch between u and v. ( 1≤u ,v ≤n )
The second line consists of n non-negative integers, the value of the i-th apple a_i. ( 1 ≤ a_i ≤ 109 )
Then there are n-1 lines, each line consists of two non-negative integers, and describe a branch between u and v. ( 1≤u ,v ≤n )
输出
Only one integer, the maximum value they can get.
样例输入
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4
样例输出
10
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | #include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+7; int n,k,cnt,cnt2,head[maxn],chi_nu[maxn],leaf,leafs[maxn],father[maxn],letime[maxn]; ll ans,cost[maxn],leaf_cost[maxn]; //cnt是每一次建树用的,cnt2是广搜时保存新的边用的,chi_nu[]是保存当前最新的每一个节点后面的叶子个数 //lea是最新叶子个数,leafs[]是第一次把叶子及其有效值加入优先队列时用来保存叶子节点的,father[]是保存每一个节点的父节点 //lettime[]是每一个叶子节点的时间戳,这样每次加入优先队列时就可以判断当前叶子节点是否最新的 //ans保存答案,cost[]保存最初每一个节点的有效值,leaf_cost[i]保存当前最新叶子节点为i的叶子那条链的有效值 bool vis[maxn],vis2[maxn]; //vis[]是删边标记用的,vis2[]是重新建树时广搜标记用的 struct bian{ int a,b; }renew[maxn]; //保存重新建树的新边用的 struct lenode{ //叶节点的最大有效值以及优先队列的节点 int u, time =0; ll l_cost=0; bool operator<( const lenode & a) const { return l_cost>a.l_cost; } }; lenode genx; //每一次删叶子节点保存的新的叶子节点及其有效值 bool flaggenxi=0; //每一次删边时是否更新其它叶子节点的标记判断 priority_queue<lenode>leafque; //优先队列,用以排序当前还存在的叶子节点,按有效值重小到大 struct node{ //邻接表节点 int to,next; } edge[2*maxn]; //邻接表 void add( int a, int b){ //邻接表加边 edge[++cnt].to=b,edge[cnt].next=head[a]; head[a]=cnt; } int DFS( int now){ //寻找叶节点以及赋值每一个节点后面存在的叶节点数,叶节点的这个数为零 int num=0,to; for ( register int i=head[now]; i; i=edge[i].next){ to=edge[i].to; if (head[to]==0)++num,leafs[++leaf]=to; else { chi_nu[to]=DFS(to); num+=chi_nu[to]; } } return num; } ll zfa( int now){ //计算叶节点的有效值 if (now==0) return 0; if (chi_nu[now]<=1) return cost[now]+zfa(father[now]); return 0; } void zfa3( int now){ //更新此节点的后面叶子个数 if (now==0) return ; --chi_nu[now]; zfa3(father[now]); } int zaoyi( int now){ //寻找叶节点 int to; for ( register int i=head[now]; i; i=edge[i].next){ to=edge[i].to; if (!vis[to]){ if (head[to]==0) return to; return zaoyi(to); break ; } } } ll zfsum( int now){ //当删叶节点时又得到一条新的链时往根节点查找有效值及更新当前叶节点的有效值 if (now==0) return 0; if (chi_nu[now]==1) return cost[now]+zfsum(father[now]); return 0; } void zfa2( int now){ //删除一个叶子节点 if (chi_nu[now]>2){ chi_nu[now]--; zfa3(father[now]); return ; } if (chi_nu[now]==1){ vis[now]=1; zfa2(father[now]); return ; } --chi_nu[now]; zfa3(father[now]); int yi=zaoyi(now); ll sumxs=leaf_cost[yi]+cost[now]; sumxs+=zfsum(father[now]); flaggenxi=1; genx.l_cost=sumxs; genx.u=yi; } void BFS(){ //第二次建树所需要的广搜,就是重新找边 queue< int >que; que.push(1); bian temp; vis2[1]=1; while (!que.empty()){ int now=que.front(); que.pop(); temp.a=now; for ( register int i=head[now];i;i=edge[i].next){ int to=edge[i].to; if (!vis2[to]){ vis2[to]=1; que.push(to); temp.b=to; renew[++cnt2]=temp; } } } } int main(){ scanf ( "%d %d" ,&n,&k); int a,b; for ( register int i=1; i<=n; ++i) scanf ( "%lld" ,&cost[i]),ans+=cost[i]; for ( register int i=1; i<=n-1; ++i){ //第一次建树 scanf ( "%d %d" ,&a,&b); add(a,b); add(b,a); } BFS(); //由于是双向的这个题,但是我的代码得是标准的单向树才能合理运行,所以的重新建树 cnt=0; memset (head,0, sizeof (head)); for ( register int i=1;i<n;++i){ //第二次重新建树 add(renew[i].a,renew[i].b); father[renew[i].b]=renew[i].a; } chi_nu[1]=DFS(1); //调用函数计算每个节点后面的叶子个数 if (leaf<=k){ //leaf<=k代表可以把所有节点吃完 printf ( "%lld\n" ,ans); return 0; } lenode te; for ( register int i=1; i<=leaf; ++i){ //计算每一个叶子节点的有效值 leaf_cost[leafs[i]]=zfa(father[leafs[i]])+cost[leafs[i]]; te.l_cost=leaf_cost[leafs[i]]; te.u=leafs[i]; leafque.push(te); } while (leaf>k){ flaggenxi=0; te=leafque.top(); leafque.pop(); while (te. time <letime[te.u]){ //运用时间戳,避免了大量的查找 te=leafque.top(); leafque.pop(); } vis[te.u]=1; zfa2(father[te.u]); ans-=te.l_cost; --leaf; if (flaggenxi){ //如果在删除叶子节点时产生其它的叶子节点更新,就更新 genx. time =++letime[genx.u]; leafque.push(genx); leaf_cost[genx.u]=genx.l_cost; //更新叶子节点有效值,第一次就是调这个bug调了好就才发现没有更新 } } printf ( "%lld\n" ,ans); return 0; } /* 8 1 4 3 2 1 2 4 2 3 2 1 3 2 6 2 4 2 5 1 7 5 8 5 5 2 4 3 2 1 1 1 2 1 5 2 3 2 4 */ |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具