【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并
【BZOJ4919】[Lydsy六月月赛]大根堆
Description
Input
Output
Sample Input
3 0
1 1
2 1
3 1
4 1
5 1
Sample Output
题解:考虑用f[i][j]表示在i节点的子树中,最大值<=j,最多能选择多少点。如何转移呢?父亲节点的f数组可以看成儿子节点的f数组对应位置相加。然后再用 当前点权值-1处的f值 +1 来更新当前点权值后面的所有f值。
为此,我们可以考虑用线段树+标记永久化维护,我们要实现维护区间最大值。然后转移的时候可以直接用线段树合并搞定。细节还是比较多的。
upd:多说一点吧。有标记的线段树进行合并时也是比较恶心的。对于区间max标记,我们要进行标记永久化。这样的话每个节点的最大值标记对整个区间就都适用。在合并a和b的某个儿子时,如果这个儿子a有b没有,那么我们可以直接让a的标记对b的儿子生效,反之亦然。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=200010;
int n,m,cnt,tot,ans;
int to[maxn],next[maxn],head[maxn],p[maxn],val[maxn],v[maxn],rt[maxn];
inline void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
bool cmp(const int &a,const int &b)
{
return val[a]<val[b];
}
struct sag
{
int ls,rs,tag,sum;
}s[maxn<<6];
inline void pushdown(int x)
{
if(s[x].ls) s[s[x].ls].sum+=s[x].sum,s[s[x].ls].tag=max(s[s[x].ls].tag+s[x].sum,s[x].tag);
if(s[x].rs) s[s[x].rs].sum+=s[x].sum,s[s[x].rs].tag=max(s[s[x].rs].tag+s[x].sum,s[x].tag);
s[x].sum=0;
}
int merge(int a,int b)
{
if(!a||!b) return a^b;
pushdown(a),pushdown(b);
if(!s[a].ls) s[a].ls=s[b].ls,s[s[a].ls].tag+=s[a].tag,s[s[a].ls].sum+=s[a].tag+s[a].sum;
else if(!s[b].ls) s[s[a].ls].tag+=s[b].tag,s[s[a].ls].sum+=s[b].tag+s[b].sum;
else s[a].ls=merge(s[a].ls,s[b].ls);
if(!s[a].rs) s[a].rs=s[b].rs,s[s[a].rs].tag+=s[a].tag,s[s[a].rs].sum+=s[a].tag+s[a].sum;
else if(!s[b].rs) s[s[a].rs].tag+=s[b].tag,s[s[a].rs].sum+=s[b].tag+s[b].sum;
else s[a].rs=merge(s[a].rs,s[b].rs);
s[a].tag+=s[b].tag;
return a;
}
void updata(int l,int r,int &x,int a,int b,int c)
{
if(!x) x=++tot;
if(a<=l&&r<=b)
{
s[x].tag=max(s[x].tag,c);
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,s[x].ls,a,b,c);
if(b>mid) updata(mid+1,r,s[x].rs,a,b,c);
}
int query(int l,int r,int x,int a)
{
if(!x||!a) return 0;
if(l==r) return s[x].tag;
pushdown(x);
int mid=(l+r)>>1;
if(a<=mid) return max(s[x].tag,query(l,mid,s[x].ls,a));
return max(s[x].tag,query(mid+1,r,s[x].rs,a));
}
void dfs(int x)
{
for(int i=head[x];i!=-1;i=next[i]) dfs(to[i]),rt[x]=merge(rt[x],rt[to[i]]);
updata(1,m,rt[x],v[x],m,query(1,m,rt[x],v[x]-1)+1);
}
void find(int x)
{
ans=max(ans,s[x].tag);
pushdown(x);
if(s[x].ls) find(s[x].ls);
if(s[x].rs) find(s[x].rs);
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
n=rd();
int i,a;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++)
{
val[i]=rd(),a=rd(),p[i]=i;
if(i!=1) add(a,i);
}
sort(p+1,p+n+1,cmp);
for(i=1;i<=n;i++)
{
if(i==1||val[p[i]]>val[p[i-1]]) m++;
v[p[i]]=m;
}
dfs(1),find(rt[1]);
printf("%d",ans);
return 0;
}
【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并的更多相关文章
- BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)
题目链接 考虑树退化为链的情况,就是求一个最长(严格)上升子序列. 对于树,不同子树间是互不影响的.仿照序列上的LIS,对每个点x维护一个状态集合,即合并其子节点后的集合,然后用val[x]替换掉第一 ...
- BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶
是不是每做道线段树进阶都要写个题解..根本不会写 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...
- 【BZOJ4919】[Lydsy六月月赛]大根堆
题解: 我觉得数据结构写成结构体还是有必要的 因为不然一道题里出现了两个相同的数据结构由于名字很像很容易出错 另外初始化用segmenttree(){ } 首先裸的dp很好想 f[i][j]表示在i点 ...
- bzoj 4919: [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 ...
- BZOJ4919:[Lydsy1706月赛]大根堆(set启发式合并)
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- BZOJ 4919: [Lydsy1706月赛]大根堆 set启发式合并
这个和 bzoj 5469 几乎是同一道题,但是这里给出另一种做法. 你发现你要求的是一个树上 LIS,而序列上的 LIS 有一个特别神奇的 $O(n\log n) $ 做法. 就是维护一个单调递增的 ...
- [BZOJ4920][Lydsy六月月赛]薄饼切割
[BZOJ4920][Lydsy六月月赛]薄饼切割 试题描述 有一天,tangjz 送给了 quailty 一张薄饼,tangjz 将它放在了水平桌面上,从上面看下去,薄饼形成了一个 \(H \tim ...
- [Lydsy1706月赛]大根堆
4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 358 Solved: 150[Submit][Stat ...
随机推荐
- Thinkphp5笔记七:设置错误页面②
更加完美的去设置错误页面. 一.准备一个错误页面 error.html,位置:thinkphp\template\index\default\error.html ,准备把前段所有的错误提示都指向这里 ...
- 开发者如何更好的选择和适应NoSQL的5个阶段
基本含义 NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨.NoSQL的拥护者们提倡运用非关 ...
- linux shell搜索某个字符串,然后在后面加上字符串?字符串后面插入字符串?sed字符串后面插入字符串?
需求描述: 今天在配置nrpe.cfg这个文件,里面有allowed_hosts的IP地址,需要加上监控主机的地址,所以首先要搜索 到这个地址,然后呢,加上监控主机的地址,考虑通过sed命令来实现 操 ...
- linux环境中,如何使用tar来创建压缩包?解压缩?
需求说明: 今天需要将一个tomcat目录打成压缩包,使用zip感觉有点慢,所以就想用tar来试试,之前一直使用tar的解压缩命令, 今天试试tar的压缩命令 操作过程: 1.通过tar的zcf选项进 ...
- pycharm使用docker镜像的python解释器,pycahrm可视化操作和管理dcoker
网上关于pycahrm怎么使用docker容器的python解释器的科普,这方面太少,一半都只介绍pycahrm怎么使用linux的解释器.首先pycahrm确保是pro版本. 下面详细的介绍步骤 首 ...
- [Arch] 02. Design principle and Software Pattern
Ref: 软件设计的七大原则 有时间的话,还需进一步深入理解. Figure, 重要的前五个原则 单一职责原则 (Simple responsibility pinciple SRP) 类的设计趋向于 ...
- java图片裁剪和java生成缩略图
一.缩略图 在浏览相冊的时候.可能须要生成相应的缩略图. 直接上代码: public class ImageUtil { private Logger log = LoggerFactory.getL ...
- C#------如何深度克隆一个对象
普通版: public static object CloneObject( object obj ) { using ( MemoryStream memStream = new MemoryStr ...
- AngularJS------命令行
如下:(‘$’符号不需要输入哦) $ ng build --发布项目
- 升级MAC OX上的Python到3.4
第1步:下载Python3.4 下载地址如下: 下载Mac OS X 64-bit/32-bit installerhttps://www.python.org/downloads/release/p ...