bzoj3252攻略 贪心+dfs序+线段树
题目链接:戳这里
3252: 攻略
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 605 Solved: 255
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
4 3 2 1 1
1 2
1 5
2 3
2 4
Sample Output
HINT
对于100%的数据,n<=200000,1<=场景价值<=2^31-1
emmm...这题一开始不太会做,后来想想发现挺简单的。
一开始的想法,这题可以转换为两种操作:一种是求点权和最大的树链,一种是把一条树链全部置为0。
然后就发现好麻烦,普通的树链剖分求不了点权和最大的树链啊,陷入江局。
如果把问题这么想就变简单了,如果每个节点存储从根到该节点的价值和,那么每次找到最大的叶节点,然后更改取走该叶节点所在链后受到影响的节点的值。
至此,此题大体转换为以下过程:
1、每次贪心的取走值最大的树链,即叶节点,能证明这是正确的。
2、修改受到影响的节点的值。
那么哪些节点受到影响了呢?
只考虑深度大于它的节点,将树上的节点分为两类:在它的子树内和不在它的子树内。
显然如果一个节点不在该节点的子树内,那么该节点到根的路径上也不会经过该节点,故不会受到影响。
如果一个节点在它的子树内,因为不能重复累加价值,所以该节点到根的路径便会少val[i]的价值,减去即可。
所以问题最终转化为:
1、每次贪心的取走值最大的树链,即叶节点。
2,从叶节点遍历到根节点,对于遍历到的每个点,把它子树内的所有点全部减去这个点的价值。
维护子树内的最大值和加减显然是dfs序+线段树的经典问题。完美解决。
注意ans,sum要开long long!
代码:
#include<bits/stdc++.h>
#define maxn 200005
using 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;
}
bzoj3252攻略 贪心+dfs序+线段树相关推荐
- [Bzoj3252]攻略(dfs序+线段树)
Description 题目链接 Solution 可以想到,每次肯定是拿最大价值为最优 考虑改变树上一个点的值,只会影响它的子树,也就是dfs序上的一个区间, 于是可以以dfs序建线段树,这样就变成 ...
- 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心
3252: 攻略 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 339 Solved: 130 [Submit][Status][Discuss] ...
- dfs序+线段树 BZOJ3252 攻略
3252: 攻略 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 496 Solved: 211 [Submit][Status][Discuss] ...
- 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树
题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...
- New Year Tree(dfs序+线段树+二进制)
题意: 给出一棵 n个节点的树,根节点为 1.每个节点上有一种颜色 ci.m次操作.操作有两种: 1 u c:将以 u为根的子树上的所有节点的颜色改为c. 2 u:询问以 u为根的子树上的所有节点的颜 ...
- 求和(dfs序+线段树)
题意: 已知有n个节点,有n−1条边,形成一个树的结构. 给定一个根节点k,每个节点都有一个权值,节点i的权值为vi. 给m个操作,操作有两种类型: 1 a x :表示将节点a的权值加上x 2 a ...
- codeforces E. Jamie and Tree LCA+dfs序+线段树
题解: 写起来还稍微有点麻烦. dfs序+线段树可以维护子树的整体修改和查询. 因此,这道题我们要往子树上靠. 我们首先从1号点进行dfs遍历,顺便求出点的dfs序和深度,然后我们采用倍增的思想,可以 ...
- Codeforces 343D Water Tree(DFS序 + 线段树)
题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...
- [CodeForces877 E. Danil and a Part-time Job]dfs序+线段树
[CodeForces877 E.Danil and a Part-time Job]dfs序+线段树 分类:Data Structure SegMent Tree dfn 1. 题目链接 [Code ...
最新文章
- 遭遇IE8下的JavaScript兼容问题
- oracle 12c chad,ORACLE 12.2RAC之问题 ora.chad OFFLINE
- Spring Boot + Mybatis——RowBoundsPlugin造成的[Mapped Statements collection already contains value]解决方案
- kafka启动后会挂掉的原因
- oracle之 Oracle归档日志管理
- LeetCode 1346. 检查整数及其两倍数是否存在(哈希)
- layui tree 加载慢_图片太多,加载慢,我用了layui里的方式,放在服务器后还是太慢!怎么解决???有没有什么优化的技巧???...
- 教你如何优雅的改写“if-else”
- k8s高可用集群_搭建高可用集群(实现方式介绍)---K8S_Google工作笔记0054
- UVA 10246 Asterix and Obelix
- Annie——一个简洁强大的轻量级视频下载神器
- mysql覆盖索引理解
- 亿网文交孟建州艺术品该怎么鉴别,代码分析
- DeviceDriver(十四):多点触摸(MT协议,Input子系统)
- MATLAB的PID调节器
- javascript特效3月12日软件速递:Mozilla Firefox发布
- docker — 容器镜像
- 站长付个人微信支付宝收款系统如何对接?
- 使用Bibtex4word在WORD2016中插入参考文献的方法(大量文献方便)
- 来了!CDEC2022全国六城首站——深圳!
热门文章
- Bash和shell
- CodeForces612AThe Text Splitting(枚举)
- html5手机远程控制电脑,手机怎么远程控制电脑?手机远程控制电脑步骤详解
- fatal: The current branch xiao has no upstream branch. To push the current branch and set the remote
- C语言十进制转换为其他进制(二进制图解+代码)
- Mat与BufferedImage相互转换
- c语言程序题文件损坏,磁盘的文件系统结构已损坏且无法使用。请在卷C上运行CHKDSK工具...
- 楼宇计算机系统设计,楼宇智能管理系统IBMS设计方案.doc
- matlab找三角网,基于MATLAB的三角网交会点坐标计算的程序设计
- 通达信量化交易接口怎么破解?