BZOJ 3252 攻略 线段树
2015-09-07 22:07
423 查看
题意:链接
方法:线段树
解析:
闲的随机的题。
看完题后看着好像挺简单的。
既然每个点的权值只会传子树,并且整个图是严格的一棵树,所以应该是跟dfs序有关。
然后去看数据范围。
尼玛HINT是什么鬼。
既然这么说了那就想想怎么做吧=-=
并且因为价值都为正的,所以显然要考虑贪心,挑k条从叶节点到根的所有点权值和最大的k条。
并且每一挑完后都需要更新。
然后有一个性质,每个点至多选一次,也就是说每个点至多被删一次。
并且根节点到叶节点链上的所有点的路径上的点权和是随着深度递增的。
所以显然我们用线段树维护一个最大值以及哪个节点取到最大值就好了。
如果当前挑出来的最大值为0了,并且还没有选够k条,直接跳出就好。
然后将这些最大值累加即可。
代码:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 200010 #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; typedef long long ll; ll n,k,tot; ll a ; ll head ,cnt; ll fa ,st ,ed ,vis ,adfn ; struct node { ll from,to,next; }edge ; void init() { memset(head,-1,sizeof(head)),cnt=1; } void edgeadd(ll from,ll to) { edge[cnt].from=from,edge[cnt].to=to,edge[cnt].next=head[from]; head[from]=cnt++; } void dfs(ll now,ll ff) { st[now]=++tot,fa[now]=ff,adfn[tot]=now; for(ll i=head[now];i!=-1;i=edge[i].next) { ll to=edge[i].to; dfs(to,now); } ed[now]=tot; } ll ma[N<<2],col[N<<2],no[N<<2]; void pushup(ll rt) { if(ma[rt<<1]>ma[rt<<1|1]) { ma[rt]=ma[rt<<1]; no[rt]=no[rt<<1]; }else { ma[rt]=ma[rt<<1|1]; no[rt]=no[rt<<1|1]; } } void pushdown(ll rt) { if(col[rt]!=0) { ma[rt<<1]+=col[rt]; ma[rt<<1|1]+=col[rt]; col[rt<<1]+=col[rt]; col[rt<<1|1]+=col[rt]; col[rt]=0; } } void build(ll l,ll r,ll rt) { if(l==r) { no[rt]=l; return; } ll mid=(l+r)>>1; build(lson); build(rson); } void update(ll L,ll R,ll l,ll r,ll rt,ll v) { if(L<=l&&r<=R) { ma[rt]+=v; col[rt]+=v; return; } pushdown(rt); ll mid=(l+r)>>1; if(L<=mid)update(L,R,lson,v); if(R>mid)update(L,R,rson,v); pushup(rt); } int main() { init(); scanf("%lld%lld",&n,&k); for(ll i=1;i<=n;i++)scanf("%lld",&a[i]); for(ll i=1;i<n;i++) { ll x,y; scanf("%lld%lld",&x,&y); edgeadd(x,y); } dfs(1,0); build(1,n,1); for(ll i=1;i<=n;i++) { update(st[i],ed[i],1,n,1,a[i]); } ll ans=0; while(k--) { if(ma[1]==0)break; ll u=adfn[no[1]]; ans+=ma[1]; while(u!=0&&!vis[u]) { update(st[u],ed[u],1,n,1,-a[u]); vis[u]=1,u=fa[u]; } } printf("%lld\n",ans); }
相关文章推荐
- linux运维实战练习-2015年8月30日课程作业
- iOS编程:学习篇(十二)
- Matlab函数总结
- UIAlertView 写在NSObject的类中没有回调
- 《笨方法学python-6》之lambda
- 黑马程序员_java 连接各种数据库的方法
- 集群,分布式,负载均衡区别联系
- Android学习0906<十一>(ViewPager,fragment碎片)
- HDU 5167 Fibonacci(DFS暴力搜索)
- Java内存模型
- 提升方法要点
- oj放苹果
- Linux重新学习--shell script--控制结构
- 幽幽的灵光射不出你想要的疯狂
- 多态测试
- Linux在批量服务器管理中实用的PS1命令提示符格式实现方法
- 使用matlab进行非线性方程组求解
- Android 笔记 6
- php 碎片笔记
- 年中总结