题目链接:点击查看

题目大意:给出一棵树,每个节点都有一个编号,现在规定每个节点的“结实程度”为其子树中所有的编号排序后相邻两个数之差的平方和,现在需要求出每个节点的“结实程度”

题目分析:因为离线+对每个子树的操作,所以可以用树上启发式合并nlogn解决问题, 对于每次更新/删除操作,因为题目的计算方法的前提是有序,并且每个编号两两都不互相重复,所以我们可以直接用一个set来维护,对于统计答案,我一开始用了一个很笨的方法,对于每个节点都遍历一遍set内的数,这样时间复杂度显然是n*n*logn的,肯定超时了,其实借助树上启发式合并不断传递的思想,对于每次更新的一个数,我们都可以在logn的时间复杂度内解决,具体实现就是先二分找到这个操作数的位置,并取出其相邻的两个数,减去之前的贡献,累加上新增加的贡献即可完成贡献,这样总时间复杂度为nlognlogn,而且牛客的评测机跑的好快,我用vector邻接表存边最后也才跑了300多ms

在代码实现方面,关于对一个数维护答案的代码部分,增加时和删除时的代码是大同小异的,但我为了方便直接CV大法了,没有考虑到代码复用的问题,可能代码看起来比较冗杂

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
#include<unordered_map>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;vector<int>node[N];set<int>st;LL sum;int son[N],num[N];LL ans[N];bool vis[N];void dfs_son(int u)
{son[u]=-1;num[u]=1;for(auto v:node[u]){dfs_son(v);num[u]+=num[v];if(son[u]==-1||num[son[u]]<num[v])son[u]=v;}
}void add(int num)
{set<int>::iterator it=st.lower_bound(num),start=st.begin(),end=st.end();end--;auto pre=it,next=it;if(it!=start)pre--;if(it!=end)next++;if(pre!=it&&next!=it)//当前插入的数在中间{sum-=1LL*(*next-*pre)*(*next-*pre);sum+=1LL*(*next-*it)*(*next-*it);sum+=1LL*(*pre-*it)*(*pre-*it);} else if(pre!=it)//在最后 {sum+=1LL*(*pre-*it)*(*pre-*it);}else if(next!=it)//在开头{sum+=1LL*(*next-*it)*(*next-*it);}else//只有一个数 {sum=0;}
}void del(int num)
{set<int>::iterator it=st.lower_bound(num),start=st.begin(),end=st.end();end--;auto pre=it,next=it;if(it!=start)pre--;if(it!=end)next++;if(pre!=it&&next!=it)//当前删除的数在中间{sum+=1LL*(*next-*pre)*(*next-*pre);sum-=1LL*(*next-*it)*(*next-*it);sum-=1LL*(*pre-*it)*(*pre-*it);} else if(pre!=it)//在最后 {sum-=1LL*(*pre-*it)*(*pre-*it);}else if(next!=it)//在开头{sum-=1LL*(*next-*it)*(*next-*it);}else//只有一个数 {sum=0;}
}void update(int u,int val)
{if(val==1){st.insert(u);add(u);}else{del(u);st.erase(u);}for(auto v:node[u]){if(vis[v])continue;update(v,val);}
}void dfs(int u,int keep)
{for(auto v:node[u]){if(v==son[u])continue;dfs(v,0);}if(son[u]!=-1){dfs(son[u],1);vis[son[u]]=true;}update(u,1);ans[u]=sum;if(son[u]!=-1)vis[son[u]]=false;if(!keep)update(u,-1);
}int main()
{
//  freopen("input.txt","r",stdin);
//  ios::sync_with_stdio(false);int n;scanf("%d",&n);for(int i=2;i<=n;i++){int fa;scanf("%d",&fa);node[fa].push_back(i);}dfs_son(1);dfs(1,1);for(int i=1;i<=n;i++)printf("%lld\n",ans[i]);return 0;
}

牛客 - 阔力梯的树(树上启发式合并)相关推荐

  1. 阔力梯的树(2020 CCPC Wannafly Winter Camp Day2 Div.12 )dsu on tree

    题解: dsu on tree dsu on tree的基本步骤就不说了 看到这题询问结点的子树问题,而且询问时离线的,首先想到的dsu on tree的这个trick. 本题的难题就是如何维护结点所 ...

  2. 牛客 Cutting Bamboos (主席树)

    题解 - 牛客 Cutting Bamboos (主席树) 题目链接: https://ac.nowcoder.com/acm/contest/889/H 题意: 给你一些竹子,q个询问,问你从第l到 ...

  3. 牛客挑战赛42 B.小睿睿的伤害(树上启发式合并)

    题意: 思路: 上面是官方题解,套路加树上启发式合并,就是这个启发式之前没写过,代码写的感觉有点繁琐. 总结:当碰到关于点对的lca具有某些性质时,可以考虑对于每个点,当这个点成为lca时求把这个点当 ...

  4. 树上启发式合并问题 ---- 2019icpc南昌 K. Tree (树上启发式合并 + 动态开点线段树)

    题目链接 题目大意: 就是给你一颗树,每个点有个权值viv_ivi​,问你有多少对(x,y)(x,y)(x,y)满足: xxx不是yyy的祖先 yyy也不是xxx的祖先 xxx和yyy的距离不超过kk ...

  5. 树上启发式合并问题 ---- D. Tree and Queries[树上启发式合并+树状数组]

    题目链接 题目大意: 就是给你一棵树,树上每个节点都有一个颜色,在你mmm次询问每次询问给你一个节点uuu和一个数字kkk,问你在uuu这颗子树里面又少种颜色的结点个数是大于kkk; 解题思路: 看到 ...

  6. 中石油训练赛 - Russian Dolls on the Christmas Tree(树上启发式合并/主席树)

    题目链接:点击查看 题目大意:给出一棵 n 个节点的树,以点 1 为根,现在对于每个节点作为根的子树求解:子树中有多少个编号不相交的连续子段,如:1 2 4 5 7,共有三个连续的段,分别为 [ 1 ...

  7. 山东理工大学第十二届ACM程序设计竞赛 - Cut the tree(树上启发式合并+线段树)

    题目链接:点击查看 题目大意:给一个具有 N 个节点的有根树,以 1 号节点为根,节点编号从 1 开始,点有点权.树的第 H 层权值为深度为 H 的所有点的点权之和.树的总权值为所有层权值的最大值.问 ...

  8. P6623-[省选联考2020A卷]树【Trie,树上启发式合并】

    正题 题目链接:https://www.luogu.com.cn/problem/P6623 题目大意 一棵树,每个节点有一个权值valival_ivali​,定义disi,jdis_{i,j}dis ...

  9. 【CF375D】Trees and Queries——树上启发式合并

    (题面不是来自Luogu) 题目描述 有一个大小为n且以1为根的树,树上每个点都有对应的颜色ci.现给出m次询问v, k,问以v为根的子树中有多少种颜色至少出现了k次. 输入格式 第一行两个数n,m表 ...

最新文章

  1. 01Python基础_09异常
  2. 做java技术天花板在哪里?我突然发现影响你晋升的竟然不是技术!
  3. 与安装应用签名不同怎么解决_天堂巴比伦 安卓游戏安装失败怎么解决
  4. 【链表】逆序打印链表
  5. 如何使用第三方日志记录提供程序替代.NET Core中的内置程序
  6. java selenium 日志_java - 支持selenium日志_java_酷徒编程知识库
  7. 怎么汇报一周开发工作情况_如何在没有经验的情况下获得第一份开发人员工作
  8. Spring、SpringBoot常见面试题与答案
  9. Ssm框架实现的学生信息管理系统
  10. python的顶级库_世界上最顶级的python库,NumpyPandas
  11. [windows]mstsc远程报:这可能是由于CredSSP 加密Oracle修正的解决方法
  12. ffmpeg-20160714-git-bin.7z
  13. 论合同管理的现状、发展趋势及重要性
  14. 新型智慧城市顶层规划与设计方案
  15. rdlc打印时多出空白页面(reportviewer).导出多出空白页(pdf,word)
  16. GEO数据库的使用(一)
  17. 登录 不输入账号密码 不能到下一个页面 没办法通过网址直接进去
  18. 你的微信接收消息也会延迟吗?原因居然出在这,一招教你轻松解决
  19. 智力开发(赛马问题)
  20. openwrt 遍译php_OpenWrt CI 在线集成编译环境使用教程

热门文章

  1. powerdns mysql_安装PowerDNS(使用MySQL后端)和Poweradmin在Debian Lenny
  2. MySQL高级 - 查询缓存 - 概述及流程
  3. 使用Docker-镜像命令
  4. leader选举的源码分析-quorumPeer.createElectionAlgorithm
  5. zookeeper的设计猜想-Follower角色
  6. Lambda表达式练习1【应用】
  7. 导入os模块执行文件和目录管理操作
  8. SpringBoot_入门-环境准备
  9. jvm_堆栈永久区详细讲解
  10. Bootstrap全局css样式_按钮