[bzoj4919][splay]大根堆

20人阅读 评论(7) 收藏 举报
分类:

4919: [Lydsy1706月赛]大根堆

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 500 Solved: 225
[Submit][Status][Discuss]
Description

给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点。每个点有一个权值v_i。
你需要将这棵树转化成一个大根堆。确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i,j,如果i在树上是j的祖先,那么v_i>v_j。
请计算可选的最多的点数,注意这些点不必形成这棵树的一个连通子树。
Input

第一行包含一个正整数n(1<=n<=200000),表示节点的个数。
接下来n行,每行两个整数v_i,p_i(0<=v_i<=10^9,1<=p_i

sol:

一开始的想法是这样的,f[i][j]表示i的子树中选出的数的权值<=j的情况下能选出的最多的点数。那么f[u]就是把f[v]全部加起来之后,把f[u][a[u]-1]+1拿去更新后面的数。也就是说要取个max,然后我们用线段树合并来优化这个过程即可。但是带标记的线段树合并写起来挺麻烦的。去看了一下网上的题解,网上是说这是个变种的lis,我一想这个tm好像很对啊。f[i][j]表示当前i子树选了j个点的最大权值的最小值。然后就可以用multiset启发式合并了。

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<set>
#include<iostream>
#define it multiset<int> 
using namespace std;
typedef long long ll;
typedef double db;
int n,m;
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
const int N=410000;
int tot,fir[N],go[N],nex[N];
inline void add(int x,int y)
{
    nex[++tot]=fir[x];fir[x]=tot;go[tot]=y;
    nex[++tot]=fir[y];fir[y]=tot;go[tot]=x;
}
it q[N];
int a[N];
inline void dfs(int u,int f)
{
    int e,v;
    it::iterator i;
    for(e=fir[u];v=go[e],e;e=nex[e])
    if(v^f)
    {
        dfs(v,u);
        if(q[u].size()<q[v].size()) q[u].swap(q[v]);
        for(i=q[v].begin();i!=q[v].end();++i) q[u].insert(*i);
    }
    i=q[u].lower_bound(a[u]);
    if(i!=q[u].end()) q[u].erase(i);
    q[u].insert(a[u]);
}
int main()
{
//  freopen("4919.in","r",stdin);
//  freopen("4919.out","w",stdout);
    n=read();
    for(int i=1;i<=n;++i)
    {
        a[i]=read();
        add(read(),i);
    }
    dfs(1,0);
    printf("%d\n",q[1].size()); 
}
查看评论

[BZOJ4919][Lydsy六月份月赛 .C][树上DP][启发式合并]大根堆

用f[i][j]表示第i个节点,最大的为j且满足条件的大根堆的大小 现场写了一个很鬼畜的线段树合并DP数组……一直RE加上时间不够就弃疗了 不过好像是有类似的做法,先挖个坑…… 题解很妙啊,考虑...
  • Coldef
  • Coldef
  • 2017-06-25 16:53:08
  • 701

[bzoj4919]大根堆

题目描述 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点。每个点有一个权值v_i。 你需要将这棵树转化成一个大根堆。确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两...
  • WerKeyTom_FTD
  • WerKeyTom_FTD
  • 2017-07-09 21:13:17
  • 605

bzoj4919 大根堆 [启发式合并]

Description: 一棵树,每个点uuu有权值val[u]val[u]val[u],要求选出最多的点,并且满足每个被选的点子树中没有权值大于等于该点权值。 Solution: 吐槽: ...
  • pocket_lengend
  • pocket_lengend
  • 2018-03-27 22:45:31
  • 54

BZOJ 4919 大根堆

Problem BZOJ Solution 一个树上lis问题。处理方式很类似于序列上的lis问题的nlogn解法。 每个节点维护一个set,set就类似于nlogn中的维护的单调序列。 ...
  • As_A_Kid
  • As_A_Kid
  • 2018-04-04 12:08:08
  • 8

bzoj4919 大根堆(线段树合并)

bzoj4919 也是雅礼集训考的一题。。。 似乎不必要用线段树合并,用个set也能又好又快的水过去。。。 先考虑最简单的树形dp怎么做; 设dp[i][j]表示当前在i节点并且选的最大不超过...
  • qq_36284842
  • qq_36284842
  • 2018-03-28 19:10:13
  • 39

hdu 4919 java大数

Exclusive or Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...
  • messyidea
  • messyidea
  • 2014-08-06 11:04:50
  • 298

启发式合并/dsu on tree 姿势

Dsu on Tree一场比赛有两道,好tm巧啊Problem 1这种方法其实就是通过性质优化的暴力。遍历时轻边优先。 首先肯定是拆位了,然后可以用trie维护一下某颗子树内的点的串,很容易统计答案...
  • jokerwyt
  • jokerwyt
  • 2017-09-16 16:34:00
  • 120

[bzoj4919][splay]大根堆

4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec Memory Limit: 256 MB Submit: 500 Solved: 225 [Submit]...
  • qq_36993218
  • qq_36993218
  • 2018-04-16 19:59:09
  • 20

[bzoj4919][Lydsy1706月赛]大根堆【dp】【启发式合并】【stl】

【题目链接】   https://www.lydsy.com/JudgeOnline/problem.php?id=4919 【题解】   很妙的一道题。考虑N∗logNN∗logNN*logN...
  • D_Vanisher
  • D_Vanisher
  • 2018-04-02 21:54:49
  • 13

[bzoj4919]大根堆——set启发式合并

题目大意: 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点。每个点有一个权值v_i。 你需要将这棵树转化成一个大根堆。确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意...
  • ylsoi
  • ylsoi
  • 2018-04-02 17:01:26
  • 24
    个人资料
    持之以恒
    等级:
    访问量: 1万+
    积分: 1840
    排名: 2万+
    最新评论