bzoj3252攻略 贪心+dfs序+线段树
来源:互联网 发布:阿里巴巴比淘宝便宜 编辑:程序博客网 时间:2024/05/18 18:00
题目链接:戳这里
3252: 攻略
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 605 Solved: 255
[Submit][Status][Discuss]
Description
题目简述:树版[k取方格数]
众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。
今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
“为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”
Input
第一行两个正整数n,k
第二行n个正整数,表示每个场景的价值
以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)
保证场景1为根节点
Output
输出一个整数表示答案
Sample Input
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4
4 3 2 1 1
1 2
1 5
2 3
2 4
Sample Output
10
HINT
对于100%的数据,n<=200000,1<=场景价值<=2^31-1
一开始的想法,这题可以转换为两种操作:一种是求点权和最大的树链,一种是把一条树链全部置为0。
然后就发现好麻烦,普通的树链剖分求不了点权和最大的树链啊,陷入江局。
如果把问题这么想就变简单了,如果每个节点存储从根到该节点的价值和,那么每次找到最大的叶节点,然后更改取走该叶节点所在链后受到影响的节点的值。
至此,此题大体转换为以下过程:
1、每次贪心的取走值最大的树链,即叶节点,能证明这是正确的。
2、修改受到影响的节点的值。
那么哪些节点受到影响了呢?
只考虑深度大于它的节点,将树上的节点分为两类:在它的子树内和不在它的子树内。
显然如果一个节点不在该节点的子树内,那么该节点到根的路径上也不会经过该节点,故不会受到影响。
如果一个节点在它的子树内,因为不能重复累加价值,所以该节点到根的路径便会少val[i]的价值,减去即可。
所以问题最终转化为:
1、每次贪心的取走值最大的树链,即叶节点。
2,从叶节点遍历到根节点,对于遍历到的每个点,把它子树内的所有点全部减去这个点的价值。
维护子树内的最大值和加减显然是dfs序+线段树的经典问题。完美解决。
注意ans,sum要开long long!
代码:
#include<bits/stdc++.h>#define maxn 200005using namespace std;typedef long long LL;int read(){char c;int sum=0,f=1;c=getchar();while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}return sum*f;}int n,k;int a[maxn],fa[maxn];struct node{int l,r;int pos;LL maxa,lazy;}tree[maxn<<2];int in[maxn],out[maxn],dfn[maxn],cur;LL sum[maxn],ans;bool vis[maxn];vector<int> edge[maxn];void dfs(int x){in[x]=++cur;dfn[cur]=x;int lens=edge[x].size();for(int i=0;i<lens;i++){int nex=edge[x][i];sum[nex]=sum[x]+a[nex];dfs(nex);}out[x]=cur;}void pushup(int id){tree[id].maxa=0;int ls=id<<1,rs=id<<1|1;if(tree[id].maxa<tree[ls].maxa){tree[id].maxa=tree[ls].maxa;tree[id].pos=tree[ls].pos;}if(tree[id].maxa<tree[rs].maxa){tree[id].maxa=tree[rs].maxa;tree[id].pos=tree[rs].pos;}}void build(int id,int l,int r){tree[id].l=l,tree[id].r=r;tree[id].lazy=0;if(l==r){tree[id].maxa=sum[dfn[l]];tree[id].pos=l;return;}int mid=l+r>>1;build(id<<1,l,mid);build(id<<1|1,mid+1,r);pushup(id);}void pushdown(int id){int ls=id<<1,rs=id<<1|1;tree[ls].lazy+=tree[id].lazy;tree[rs].lazy+=tree[id].lazy;tree[ls].maxa-=tree[id].lazy;tree[rs].maxa-=tree[id].lazy;tree[id].lazy=0;}void add(int id,int ql,int qr,LL x){int l=tree[id].l,r=tree[id].r;if(l==ql && r==qr){tree[id].lazy+=x;tree[id].maxa-=x;return;}pushdown(id);int mid=l+r>>1;if(qr<=mid) add(id<<1,ql,qr,x);else if(ql>mid) add(id<<1|1,ql,qr,x);else add(id<<1,ql,mid,x),add(id<<1|1,mid+1,qr,x);pushup(id);}int main(){n=read();k=read();for(int i=1;i<=n;i++)a[i]=read();sum[1]=a[1];for(int i=1;i<n;i++){int u=read(),v=read();edge[u].push_back(v);fa[v]=u;}dfs(1);build(1,1,n);while(k--){ans+=tree[1].maxa;for(int i=dfn[tree[1].pos];!vis[i] && i;i=fa[i]){vis[i]=true;add(1,in[i],out[i],a[i]);}}printf("%lld\n",ans);return 0;}
阅读全文
0 0
- bzoj3252攻略 贪心+dfs序+线段树
- dfs序+线段树 BZOJ3252 攻略
- BZOJ3252 攻略 [树链剖分][不用线段树]
- 【BZOJ】【P3252】【攻略】【题解】【贪心+dfs序+线段树】
- BZOJ 3235 攻略 贪心+线段树+dfs序列
- 【BZOJ3252】攻略
- bzoj3252 攻略
- BZOJ3252 攻略
- [bzoj3252]攻略
- 【bzoj3252】攻略
- BZOJ3252: 攻略
- BZOJ3252 攻略
- 3252: 攻略 dfs序+线段树
- BZOJ 3252攻略 dfs序+线段树
- BSOJ4851:攻略 贪心+线段树
- [bzoj3252][NSOI2017]攻略
- bzoj 3252: 攻略 (线段树+DFS序)
- (线段树+dfs序)
- display:table-cell
- Redis基本类型和底层实现
- 基础练习 数的读法
- 线程池ThreadPoolExecutor与java.util.concurrent.RejectedExecutionException异常
- 代码重构之重新组织函数
- bzoj3252攻略 贪心+dfs序+线段树
- android在布局中动态增加view时的层级控制
- Desert King POJ
- 双列集合(Map)
- 2014-03-03-ue快速编译运行及激活
- React常见问题梳理
- 【OpenCV入门教程之八】线性邻域滤波专场:方框滤波、均值滤波与高斯滤波
- 罗尔(Rolle)、拉格朗日(Lagrange)和柯西(Cauchy)三大微分中值定理的定义
- 分享链小程序开发源码分析