题解 「BZOJ4919 Lydsy1706月赛」大根堆
题目大意
给出一个 \(n\) 个点的树,每个点有权值,从中选出一些点,使得满足大根堆的性质。(即一个点的祖先节点如果选了那么该点的祖先节点的权值一定需要大于该点权值)
问能选出来的大根堆的最大大小。\(n\le 2\times 10^5\)
线段树合并
跟尧姐一起想的。
首先不难想到 dp,我们可以设 \(f_{u,i}\) 表示 \(u\) 子树内选出顶点权值 \(\le i\) 的大根堆的最大大小。我们可以列出转移式:
\]
然后我们发现这个东西似乎可以线段树合并转移。具体来说我们每次先把儿子的线段树合并起来,然后计算以当前节点为根的大根堆的最大大小。
不难发现,我们需要实现区间取 \(\max\),单点查询。这个东西如果要硬上的话似乎是不好搞的,因为线段树合并似乎不支持懒标记(此处存疑)。
接着思考,可以发现的是,我们每次修改的一定是一段区间,而且如果能够修改肯定是区间 \(+1\)。于是,我们就可以维护差分数组,然后在线段树上二分找到修改的端点即可。
时间复杂度 \(\Theta(n\log n)\),空间复杂度 \(\Theta(n\log n)\)。
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define INF 0x7f7f7f7f
#define MAXN 200005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
vector <int> G[MAXN];
int n,uni,res,f[MAXN],rt[MAXN],tmp[MAXN],value[MAXN];
struct Segment{
#define MAXM MAXN*100
int cnt,son[MAXM][2],sum[MAXM];
void modify (int &x,int l,int r,int pos,int val){
if (!x) x = ++ cnt;sum[x] += val;
if (l == r) return ;
int mid = (l + r) >> 1;
if (pos <= mid) modify (son[x][0],l,mid,pos,val);
else modify (son[x][1],mid + 1,r,pos,val);
}
int query (int x,int l,int r,int ql,int qr){
if (!x) return 0;
if (ql > qr) return 0;
if (l >= ql && r <= qr) return sum[x];
int mid = (l + r) >> 1,res = 0;
if (ql <= mid) res += query (son[x][0],l,mid,ql,qr);
if (qr > mid) res += query (son[x][1],mid + 1,r,ql,qr);
return res;
}
int Merge (int x,int y){
if (!x || !y) return x + y;
sum[x] += sum[y];
son[x][0] = Merge (son[x][0],son[y][0]);
son[x][1] = Merge (son[x][1],son[y][1]);
return x;
}
int find (int x,int l,int r,int t){
if (!x) return r;
if (l == r) return l;
int mid = (l + r) >> 1;
if (t < sum[son[x][0]]) return find (son[x][0],l,mid,t);
else return find (son[x][1],mid + 1,r,t - sum[son[x][0]]);
}
}Tree;
void dfs (int u){
f[u] = 1;
for (Int v : G[u]){
dfs (v);
rt[u] = Tree.Merge (rt[u],rt[v]);
}
f[u] = Tree.query (rt[u],1,uni,1,value[u] - 1) + 1;
Tree.modify (rt[u],1,uni,value[u],1);
int pos = Tree.find (rt[u],1,uni,f[u]);
if (Tree.query (rt[u],1,uni,1,pos) > f[u]) -- pos;
if (pos < uni) Tree.modify (rt[u],1,uni,pos + 1,-1);
}
signed main(){
read (n);
for (Int i = 1,fa;i <= n;++ i) read (value[i],fa),G[fa].push_back (i),tmp[i] = value[i];
sort (tmp + 1,tmp + n + 1),uni = unique (tmp + 1,tmp + n + 1) - tmp - 1;
for (Int i = 1;i <= n;++ i) value[i] = lower_bound (tmp + 1,tmp + uni + 1,value[i]) - tmp;
dfs (1);write (Tree.query (rt[1],1,uni,1,uni)),putchar ('\n');
return 0;
}
set 启发式合并
by @自为风月马前卒
本质上来说是个贪心???
可以发现的是,在大根堆大小相同的时候,我们肯定想要顶点的权值尽可能小,这样就对后面合并更优。
于是,我们可以考虑把当前点与子树进行合并,我们如果子树内有比当前点更大的值,我们发现答案不会变,直接替换 set 中比它与它相邻的树即可。否则直接加进来即可。
时间复杂度 \(\Theta(n\log^2n)\),空间复杂度 \(\Theta(n)\)。
\(\texttt{Code}\)
#include<bits/stdc++.h>
#define sit multiset<int>::iterator
using namespace std;
const int MAXN = 2e5 + 10;
inline int read() {
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
vector<int> v[MAXN];
multiset<int> s[MAXN];
int N, val[MAXN];
void dfs(int x, int fa) {
for(int i = 0; i < v[x].size(); i++) {
int to = v[x][i];
if(to == fa) continue;
dfs(to, x);
if(s[to].size() > s[x].size()) swap(s[to], s[x]);
for(sit it = s[to].begin(); it != s[to].end(); it++)
s[x].insert(*it);
s[to].clear();
}
sit it = s[x].lower_bound(val[x]);
if(it != s[x].end()) s[x].erase(it);
s[x].insert(val[x]);
}
main() {
N = read();
for(int i = 1; i <= N; i++) {
val[i] = read();
int x = read();
v[i].push_back(x); v[x].push_back(i);
}
dfs(1, 0);
printf("%d", s[1].size());
return 0;
}
题解 「BZOJ4919 Lydsy1706月赛」大根堆的更多相关文章
- BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶
是不是每做道线段树进阶都要写个题解..根本不会写 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...
- bzoj4919 [Lydsy1706月赛]大根堆
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- BZOJ4919:[Lydsy1706月赛]大根堆(set启发式合并)
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- BZOJ4919 [Lydsy1706月赛]大根堆 【dp + 启发式合并】
题目链接 BZOJ4919 题解 链上的\(LIS\)维护一个数组\(f[i]\)表示长度为\(i\)的\(LIS\)最小的结尾大小 我们可以用\(multiset\)来维护这个数组,子树互不影响,启 ...
- BZOJ4921「Lydsy1706月赛」互质序列
吐槽一下BZOJ没有C++11 题还是不难的 BZOJ 4921 题意 在长度为$ n$的数列中去掉非空的连续一段并保证剩下数字不少于$ 2$ 求合法的所有方案中剩下数字的最大公约数的总和 $Sol ...
- 题解 「BJOI2018 治疗之雨」
题目传送门 题目大意 有一个初始为 \(p\) 的数,每次操作分为以下两个: 有 \(\frac{1}{m+1}\) 的概率$+1,但是中途 \(p\) 的最大值只能为 \(n\)$ 有 \(k\) ...
- 【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并
[BZOJ4919][Lydsy六月月赛]大根堆 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...
- bzoj 4919 [Lydsy1706月赛]大根堆 set启发式合并+LIS
4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 599 Solved: 260[Submit][Stat ...
- [Lydsy1706月赛]大根堆
4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 358 Solved: 150[Submit][Stat ...
随机推荐
- go GC垃圾回收原理
目录 1.前言 2. 垃圾回收算法 3. Golang垃圾回收 3.1 垃圾回收原理 3.2 内存标记(Mark) 3.3 三色标记 3.4 Stop The World 4. 垃圾回收优化 4.1 ...
- a、b、n为正整数且a>b,证明:若n|(a^n-b^n),则n|(a^n-b^n)/(a-b).
- MySQL列举常见的关系型数据库和非关系型都有那些?
关系型数据库: Oracle.DB2.Microsoft SQL Server.Microsoft Access.MySQL 非关系型数据库: NoSql.Cloudant.MongoDb.redis ...
- AWS扩容EC2实例根空间
文章原文 aws 端操作 先在EC2 实例中选中磁盘 然后打开跟设备 修改大小后保存 ec2 端操作 lsblk 查看当前设备的磁盘编号 df -T -H 查看扩容前的空间大小并确定磁盘格式 grow ...
- springMVC学习总结(一) --springMVC搭建
springMVC学习总结(一) --springMVC搭建 搭建项目 1.创建一个web项目,并在项目中的src文件夹下创建一个包com.myl.controller. 2.添加相应jar包 3.在 ...
- noip模拟42
A. 卷 发现乘积足以爆 \(long\) \(long\),但是数据随机,可以略忽略精度问题 一个快速降低数的级别的方法是取对数,由于有性质 \(log(x * y)=logx+logy\),合并时 ...
- 性能测试必备命令(4)- pstree
性能测试必备的 Linux 命令系列,可以看下面链接的文章哦 https://www.cnblogs.com/poloyy/category/1819490.html 介绍 显示进程树 语法格式 ps ...
- weblogic漏洞分析之CVE-2017-10271
weblogic漏洞分析之CVE-2017-10271 一.环境搭建 1)配置docker 这里使用vulhub的环境:CVE-2017-10271 编辑docker-compose.yml文件,加入 ...
- 记录一次sql注入绕过
目标:http://www.xxxxx.net/temp.asp?ID=10359 通过 and 1=1 and 1=2 测试发现存在拦截 首先想到 and 空格 = 可能存在触发规则 一般遇到这种情 ...
- [闻缺陷则喜]关于boost的想法
公司有个大约2万行的项目,用到了boost,我想取消掉不用boost.理由:一,可理解性差,除了高手很难弄懂.二,类太多,光头文件就1万多.大点的团队四五个高手,每人用一个boost类.高手流失后,很 ...