题目链接:点击查看

题目大意:给出一棵有向树,每个节点都有一个初始的权值 a[ i ] ,和一个通过计算得到的权值 mid[ i ] ,mid 数组的计算方法如下:mid[ u ] 为结点 u 及其子树中所有 a[ i ] 的中位数,现在问如果可以令其中一个节点的 a[ i ] 变为 1e5,如何选择可以使得所有节点的 mid[ i ] 之和最大

题目分析:乍一看题目可能比较复杂,但是一步一步分析下来可能就能找到突破口了

首先是子树,对于子树上进行操作,我们可以跑出整棵树的dfs序,这样就将子树上的操作转换为区间上的操作了

其次是中位数,经过上面dfs序的转换,我们现在的目标转换为了如何求一段区间上的中位数,换句话说,设 sz[ i ] 为点 i 的子树大小,现在需要求一段区间上第 ( sz[ i ] + 1 ) / 2 大的数是什么,区间上第 k 大的数,这里可以用主席树解决

再分析一下题意,将一个节点的权值 a 变为 1e5 ,1e5 在这个题目中相当于无穷大,如果节点 i 的 a[ i ] 变为 1e5 后,根据题意可知,其只会对特定的祖先产生影响,这些特定的祖先 x 必须满足 mid[ x ] >= a[ i ] ,这样当 a[ i ] 变为 1e5 后,祖先 x 的中位数就会变大为原本子树中第 ( sz[ i ] + 1 ) / 2 + 1 大的数了

这样我们可以通过dfs序和主席树,将 cur_mid[ i ] 和 next_mid[ i ] 预处理出来,其意义分别为结点 i 的中位数和结点 i 的中位数的下一个数

接下来就可以暴力枚举每个顶点,然后计算当前节点的权值 a 变为 1e5 后的影响了,不难发现,如果某一个权值 a[ i ] 变为 1e5 后,总的答案只会变大,不会变小,那么我们不妨设 sum 为所有 cur_mid[ i ] 之和,mmax 为变化后可以增加的答案,那么最终答案就是 sum + mmax 了

关于如何暴力枚举,我们可以借助 dfs 和树状数组来实现,树状数组中的每个点,其下标的意义是:祖先的中位数大小,维护的权值的意义是:如果更改子树中的结点 a[ v ] 为 1e5 后,当前节点可以提供的贡献

这样在枚举点 i 时,将其变化的值插入到树状数组中,也就是 next_mid[ i ] - cur_mid[ i ] 插入到位置 cur_mid[ i ] 中,同时查询点 i 的权值 a 更改为 1e5 后祖先节点的贡献,也就是 query( 100000 ) - query( a[ i ] - 1 ) 了,其意义就是查询祖先的中位数位于 [ a[ i ] , inf ] 中的贡献

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e5+100;vector<int>node[N];//邻接表 int tot,L[N],R[N],sz[N];//树链剖分用 int cur_mid[N],next_mid[N];//题目用 LL sum,mmax;
/*树状数组*/
LL c[N];int lowbit(int x)
{return x&(-x);
}void update(int pos,int val)
{while(pos<N){c[pos]+=val;pos+=lowbit(pos);}
}LL query(int pos)
{LL ans=0;while(pos){ans+=c[pos];pos-=lowbit(pos);}return ans;
}
/*树状数组*/
/*主席树*/
struct Node
{int l,r;int sum;
}tree[N*20];int cnt,root[N],a[N];void update(int num,int &k,int l,int r)
{tree[cnt++]=tree[k];k=cnt-1;tree[k].sum++;if(l==r)return;int mid=l+r>>1;if(num<=mid)update(num,tree[k].l,l,mid);elseupdate(num,tree[k].r,mid+1,r);
}int query(int i,int j,int k,int l,int r)//i:左端点根节点编号,j:右端点根节点编号,k:第k大的数,l,r:区间[l,r]
{int d=tree[tree[j].l].sum-tree[tree[i].l].sum;if(l==r)return l;int mid=l+r>>1;if(k<=d)return query(tree[i].l,tree[j].l,k,l,mid);elsereturn query(tree[i].r,tree[j].r,k-d,mid+1,r);
}
/*主席树*/
void dfs(int u)
{sz[u]=1;L[u]=++tot;root[tot]=root[tot-1];update(a[u],root[tot],1,N);for(auto v:node[u]){dfs(v);sz[u]+=sz[v];}R[u]=tot;if(sz[u]==1){cur_mid[u]=a[u];next_mid[u]=100000;sum+=cur_mid[u];}else{int mid=(sz[u]+1)>>1;cur_mid[u]=query(root[L[u]-1],root[R[u]],mid,1,N);next_mid[u]=query(root[L[u]-1],root[R[u]],mid+1,1,N);sum+=cur_mid[u];}
}void DFS(int u)
{update(cur_mid[u],next_mid[u]-cur_mid[u]);mmax=max(mmax,query(100000)-query(a[u]-1));for(auto v:node[u])DFS(v);update(cur_mid[u],cur_mid[u]-next_mid[u]);
}void init()
{for(int i=0;i<N;i++)node[i].clear();root[0]=0;tree[0].l=tree[0].r=tree[0].sum=0;cnt=1;sum=tot=mmax=0;
}int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);int n;while(scanf("%d",&n)!=EOF){init();for(int i=1;i<=n;i++)scanf("%d",a+i);for(int i=2;i<=n;i++){int x;scanf("%d",&x);node[x].push_back(i);}dfs(1);DFS(1);printf("%lld\n",mmax+sum);}return 0;
}

HDU - 5788 Level Up(主席树+dfs序+树状数组)相关推荐

  1. bzoj 2434 [Noi2011]阿狸的打字机(AC自动机+fail树+dfs序+树状数组)

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 3521  Solved: 1913 [Submit][S ...

  2. bzoj3252攻略(线段树+dfs序)或者(树链剖分+dfs)

    3252: 攻略 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 1341 Solved: 642 [Submit][Status][Discuss] ...

  3. DFS序——树链剖分前驱知识

    目录 定义:dfs序:每个节点在dfs深度优先遍历中的进出栈的时间序列. 性质:dfs序可以把一棵树区间化,即可以求出每个节点的管辖区间. 对于一棵树的dfs序而言,同一棵子树所对应的一定是dfs序中 ...

  4. 【dfs序+树状数组】多次更新+求结点子树和操作,牛客小白月赛24 I题 求和

    前置知识点 dfs遍历 树状数组/线段树知识 链接 I题 求和. 题意 已知有 n 个节点,有 n−1 条边,形成一个树的结构. 给定一个根节点 k,每个节点都有一个权值,节点i的权值为 vi 给 m ...

  5. BZOJ_3252_攻略_线段树+dfs序

    BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...

  6. 计蒜客(青出于蓝胜于蓝) dfs序+树状数组

    武当派一共有 n 人,门派内 n 人按照武功高低进行排名,武功最高的人排名第 1,次高的人排名第 2,... 武功最低的人排名 第 n.现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师 ...

  7. 【BZOJ3439】Kpm的MC密码,trie树+dfs序+主席树

    Time:2016.05.07 Author:xiaoyimi 转载注明出处谢谢 传送门 思路: 1.have a trie,还得是倒着建的,记录每个结尾节点的id(可能会有重复,所以开一个vecto ...

  8. 2021牛客多校7 F. xay loves trees(主席树+DFS序)

    题意:有两颗n个点的树,找出最大子集,满足如下条件: 该点集在树1上为一条连续的链 该点集在树2上,两两无任何祖先关系 思路: 对于条件2: ​ 点u如果是点v的祖先,那么u的子树一定包含v,即一定包 ...

  9. HDU 6203 ping ping ping (在线倍增lca+DFS序+树状数组)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6203 #include<bits/stdc++.h> using namespace st ...

最新文章

  1. UIKit框架使用总结--看看你掌握了多少
  2. NGUI创建Camera参数为Simple 2D的UI UI对象的结构UI Root(2D)
  3. Android之ndk之用arm-linux-androideabi工具通过地址找到具体哪里崩溃
  4. Windows 创建符号链接
  5. struct lnode是什么结构类型_【自考】数据结构第三章,队列,期末不挂科指南,第4篇
  6. MFC工程按USB插口显示所有USB设备及插口(包括安卓)
  7. Python 读入Excel表时如何判空NaN
  8. 赛尔笔记 | 通用领域条件性知识图谱数据集
  9. 2019年10月全国程序员工资统计,一半以上的职位5个月没招到人~
  10. mysql关系代数表达式,【数据库复习】关系代数
  11. This dependency was not found: * common/stylus/index.styl in ./src/main.js
  12. 2021年高处安装、维护、拆除证考试及高处安装、维护、拆除复审模拟考试
  13. 近期有面试的必看!带你手撸红黑树,终获offer
  14. 联想电脑G40无法使用 非要睡眠后才能启用wifi
  15. 十分钟实现鼠标悬停效果,CSS3悬停效果
  16. vue里 a(){} 和a:()=>{}的区别
  17. 关于vue-cli3的浏览器兼容性
  18. python写水仙花的作文_怎样背英语单词才高效?
  19. 利用python request细雨筹爬虫
  20. 什么是极客?听听他们怎么说

热门文章

  1. java 绝对路径_java 获取绝对路径
  2. 根目录android结构,android系统盘根目录中的(文件)谁给讲一下是干什么的?
  3. aix oracle 内存限制,请教 AIX 与 Linux 中,怎样分析Oracle的内存占用?
  4. 创建springmvc配置
  5. Nacos源码NacosServiceRegistryAutoConfiguration
  6. Nginx关于浏览器缓存相关的配置指令
  7. 原始Junit测试Spring的问题
  8. Bean的依赖注入的数据类型
  9. POI文件导入:需求说明
  10. flume案例-文件数据采集-步骤分析