题意是给你一棵树 n个点 n-1条边 起点是1 每个点都有权值 每次能从根节点走到叶子节点 经行k次游戏 每次都是从1开始 拿过的点的权值不能拿第二次 问最大权值和;
开始看到题时也没想到什么方法 就按照常规的来 结果超时了 试着优化了好多次 最后过了 百度题解说是树链剖分 醉了 还没学!!!
?
说说我的做法吧 map【i】=a表示i节点的跟节点为a节点 从所有叶子节点开始入队(有点队列里有三个变量 分别是节点编号 权值 深度 优先级看代码 里面有点贪心的意思) 每次走根节点 如果根节点没走过 则走它 并把该店权值变为0 否则直接跳到1这个节点(如果一个个跳可能会超时)再入队 当出队的编号为1时并且拿的个数小于游戏次数 则拿 否则结束 在跑深度的时候有个优化 开始没有超时了 如果该节点深度已知了 则以后的根节点就不用跑了!!! 具体看代码吧
?
?
#include
#include
#include
#include
using namespace std
; int map
[100010
],mark
[100010
]; int Deep
[100010
]; __int64 num
[100010
]; struct node
{ __int64 value
; int ii
; int deep
; bool operator < (const node
& x
) const { return deep
<x
.deep
||(deep
==x
.deep
&&value
<x
.value
); } }a
; int main() { int T
,i
,j
,n
,k
,r
=1
; scanf
("%d"
,&T
); while(T
--) { scanf
("%d%d"
,&n
,&k
); for(i
=1
;i
<=n
;i
++) { scanf
("%I64d"
,&num
[i
]); } memset
(mark
,0
,sizeof(mark
)); for(i
=1
;i
<n
;i
++) { int x
,y
; scanf
("%d%d"
,&x
,&y
); mark
[x
]=1
; map
[y
]=x
; } priority_queue
<node
>Q
; memset
(Deep
,0
,sizeof(Deep
)); for(i
=1
;i
<=n
;i
++) { if(mark
[i
]==0
) { int x
=map
[i
]; int d
=1
; while(x
!=1
) { if(Deep
[x
]>0
) {d
+=Deep
[x
];break;} x
=map
[x
]; d
++; } x
=i
; while(x
!=1
) { if(Deep
[x
]>0
) break; Deep
[x
]=d
; x
=map
[x
]; d
--; } a
.deep
=Deep
[i
]; a
.value
=num
[i
]; a
.ii
=i
; Q
.push
(a
); } } //for(i=1;i<=n;i++) //printf("%d ^^^ %d\n",i,Deep[i]);
__int64 sum
=0
; int cont
=0
; while(!Q
.empty
()) { a
=Q
.top
(); Q
.pop
(); int x
=map
[a
.ii
]; /*while(num[x]==0&&x!=1) { x=map[x]; }*/
if(a
.ii
==1
) { a
.value
+=num
[1
]; num
[1
]=0
; sum
+=a
.value
; cont
++; if(cont
>=k
) break; } else { if(num
[x
]==0
) { a
.ii
=1
; a
.deep
=0
; } else { a
.ii
=x
; a
.deep
=Deep
[x
]; a
.value
+=num
[x
]; num
[x
]=0
; } Q
.push
(a
); } } printf
("Case #%d: %I64d\n"
,r
++,sum
); } return 0
; }
?
?