[loj3014]独特的城市
约定:一棵树的深度定义为其中到根最远的点到根的距离
考虑节点$x$的答案:
任取一条直径,根据直径的性质,到$x$较远的直径端点一定是到$x$最远的点之一
由此,不难证明对于$x$独特的点,一定在$x$到"到$x$较远的直径端点"的路径上
分别以直径的两个端点为根(做两次),每一次求出$x$到根路径上所有对$x$独特的点的特产数,根据前面所述,两次的最大值即为最终答案
关于这件事情,维护一个"目前独特"的集合$S$,具体定义如下:
$k$到根路径上的节点$x$中(不包括$k$),满足不存在$k$子树外的节点$y\ne x$,使得$k$到$x$和$y$的距离相等("$k$子树"指"以$k$为根的子树")
当递归到节点$k$时,令$mx$为$k$子树深度,将$S$中到$k$距离不超过$mx$的节点都删除,此时$S$即$k$到根路径上所有与对$k$独特的点(所构成的集合),求出其中特产数即可
接下来,考虑递归儿子$son$,令$mx$为以$k$的其余儿子子树深度的最大值+1,将$S$中到$k$距离不超过$mx$的节点都删除,然后在加入$k$(显然满足条件),并在递归完$son$后还原$S$
显然,这样做的复杂度过高,我们需要优化实现:
将$S$用一个栈维护(栈顶深度最大),"将$S$中到$k$距离不超过$mx$的节点都删除"即不断弹出栈顶
将树长链剖分,(对于节点$k$)令$mx$为$k$子树深度,$cmx$为轻儿子子树深度的最大值+1,接下来交换之前操作的顺序,即先递归重儿子,再递归轻儿子,最后统计答案
考虑递归重儿子,即将$S$中到$k$距离不超过$cmx$的节点都删除,而递归轻儿子和统计答案都是将$S$中到$k$距离不超过$mx$的节点都删除,也就不需要还原,直接操作即可
统计答案后,也不需要还原$S$,假设以此法删除的点$x$,由于删去的是到$k$距离不超过$mx$的节点,即$k$子树内必然存在节点$y$使得$k$到$x$和$y$的距离相等
那么对$x$子树内、$k$子树外的点$z$,对于$z$来说$x$一定不"独特",只需要令$y'$为将$y$向上爬$k$到$lca(k,z)$的距离步后的节点,此时$z$到$x$和$y'$的距离显然相等
由此,发现最多在$S$中加入$o(n)$个元素,那么也即至多删除$o(n)$次,复杂度为$o(n)$

1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 200005
4 struct Edge{
5 int nex,to;
6 }edge[N<<1];
7 stack<int>st;
8 int E,n,m,x,y,a[N],head[N],dep[N],l[N],cl[N],mx[N],tot[N],ans[N];
9 void add(int x,int y){
10 edge[E].nex=head[x];
11 edge[E].to=y;
12 head[x]=E++;
13 }
14 void dfs(int k,int fa,int s){
15 dep[k]=s;
16 mx[k]=l[k]=cl[k]=0;
17 for(int i=head[k];i!=-1;i=edge[i].nex)
18 if (edge[i].to!=fa){
19 dfs(edge[i].to,k,s+1);
20 int x=l[edge[i].to]+1;
21 if (l[k]<x){
22 mx[k]=edge[i].to;
23 swap(l[k],x);
24 }
25 cl[k]=max(cl[k],x);
26 }
27 }
28 void add(int k){
29 st.push(k);
30 if (++tot[a[k]]==1)ans[0]++;
31 }
32 void del(){
33 if (--tot[a[st.top()]]==0)ans[0]--;
34 st.pop();
35 }
36 void calc(int k,int fa){
37 if (fa)add(fa);
38 while ((!st.empty())&&(dep[k]-dep[st.top()]<=cl[k]))del();
39 if (mx[k])calc(mx[k],k);
40 while ((!st.empty())&&(dep[k]-dep[st.top()]<=l[k]))del();
41 ans[k]=max(ans[k],ans[0]);
42 for(int i=head[k];i!=-1;i=edge[i].nex)
43 if ((edge[i].to!=fa)&&(edge[i].to!=mx[k]))calc(edge[i].to,k);
44 if ((!st.empty())&&(st.top()==fa))del();
45 }
46 int main(){
47 scanf("%d%d",&n,&m);
48 memset(head,-1,sizeof(head));
49 for(int i=1;i<n;i++){
50 scanf("%d%d",&x,&y);
51 add(x,y);
52 add(y,x);
53 }
54 for(int i=1;i<=n;i++)scanf("%d",&a[i]);
55 dfs(1,0,0);
56 x=1;
57 for(int i=2;i<=n;i++)
58 if (dep[x]<dep[i])x=i;
59 dfs(x,0,0);
60 calc(x,0);
61 x=1;
62 for(int i=2;i<=n;i++)
63 if (dep[x]<dep[i])x=i;
64 dfs(x,0,0);
65 calc(x,0);
66 for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
67 }
[loj3014]独特的城市的更多相关文章
- [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分
题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...
- 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)
LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...
- 题解 [JOI 2019 Final] 独特的城市
题面 解析 首先有一个结论, 对一个点\(x\)有贡献的城市 肯定在它到离它较远的直径的端点的链上. 假设离它较远的端点是\(S\), 如果有一个点\(u\)不在\(x\)到\(S\)的链上, 却对\ ...
- loj 3014「JOI 2019 Final」独特的城市
loj 我本来是直接口胡了一个意思一样的做法的,但是因为觉得有点假+实现要用并查集(?)就卡了好一会儿... 对于一个点\(x\)来说,独特的点一定在它的最长链上,如果有独特的点不在最长链上,那么最长 ...
- JOI 2019 Final合集
JOI 2019 Final 合集 #3010. 「JOI 2019 Final」勇者比太郎 其实如果读懂题了就是水题了 题目就是让你求满足条件的\(JOI\),使得\(O\)在\(J\)同行的 ...
- 洛谷 P 5 3 0 4 [GXOI/GZOI2019]旅行者
题目描述 J 国有 n 座城市,这些城市之间通过 m 条单向道路相连,已知每条道路的长度. 一次,居住在 J 国的 Rainbow 邀请 Vani 来作客.不过,作为一名资深的旅行者,Vani 只对 ...
- JOI2013-2019
代码自己去LOJ看 JOI2013 彩灯 把序列划分成若干极长交替列,那么最优的方案一定是将一个极长交替列翻转使得连续的三个极长交替列合成一个.计算相邻三个极长交替列长度的最大值即可. 搭乘IOI火车 ...
- 【JZOJ6419】模拟旅行&【BZOJ5506】【luoguP5304】旅行者
description 某国有n座城市,这些城市之间通过m条单向道路相连,已知每条道路的长度. 不过,小X只对其中k座城市感兴趣. 为了更好地规划模拟旅行路线,提升模拟旅行的体验,小X想要知道他感兴趣 ...
- 「JOI2019 Final」解题报告
传送门 「JOI2019 Final」勇者比太郎 看懂题就很简单了,后缀和随便维护一下就好了,别用树状数组强加一个\(\log\)就行. 「JOI2019 Final」画展 显然可以先把所有的画框按大 ...
随机推荐
- HTML基本标记
头部标记 <head></head> 说明:元素的作用范围是整篇文档.元素中可以有元信息定义.文档样式表定义和脚本等信息,定义在HTML语言头部的内容往往不会在网页上直接显示. ...
- 基于Hexo+Github Pages搭建的博客
概念 Github Pages可以被认为是用户编写的.托管在github上的静态网页.使用Github Pages可以为你提供一个免费的服务器,免去了自己搭建服务器和写数据库的麻烦.此外还可以绑定自己 ...
- Go语言核心36讲(Go语言基础知识二)--学习笔记
02 | 命令源码文件 我们已经知道,环境变量 GOPATH 指向的是一个或多个工作区,每个工作区中都会有以代码包为基本组织形式的源码文件. 这里的源码文件又分为三种,即:命令源码文件.库源码文件和测 ...
- 独家对话阿里云函数计算负责人不瞋:你所不知道的 Serverless
作者 | 杨丽 出品 | 雷锋网产业组 "Serverless 其实离我们并没有那么遥远". 如果你是一名互联网研发人员,那么极有可能了解并应用过 Serverless 这套技术体 ...
- java 文档自动生成的神器 idoc
写文档 作为一名开发者,每个人都要写代码. 工作中,几乎每一位开发者都要写文档. 因为工作是人和人的协作,产品要写需求文档,开发要写详细设计文档,接口文档. 可是,作为一个懒人,平时最讨厌的一件事情就 ...
- Upload-labs通关指南(上) 1-10
Upload-labs 所有文章和随笔(随笔将不于csdn更新)将于我的个人博客(移动端暂未适配)第一时间更新. 一些网站存在文件上传接口,一旦存在这个接口就有可能存在漏洞. 文件上传漏洞的逻辑是将一 ...
- Vue Router 常见问题(push报错、push重复路由刷新)
Vue Router 常见问题 用于记录工作遇到的Vue Router bug及常用方案 router.push报错,Avoided redundant navigation to current l ...
- mysql锁场景及排查
1.查询长时间不返回: 在表 t 执行下面的 SQL 语句: mysql> select * from t where id=1; 查询结果长时间不返回. 一般碰到这种情况的话,大概率是表 t ...
- LDAP-初见
目录 什么是LDAP? LDAP 协议能解决什么问题? Spring Boot中使用LDAP来统一管理用户信息 添加用户 连接LDAP服务端 什么是LDAP? LDAP 的全称是 Lightweigh ...
- 微信h5跳转小程序wx-open-launch-weapp开放标签不显示(已解决)
前言: 前几天成功对接了跳转第三方小程序的功能,今天有个页面有需要对接.但是奇怪的是用的和上次一模一样的配置,但就是死活不显示wx-open-launch-weapp这个开放标签的按钮,看不到任何效果 ...