题目链接:

[JOI 2019 Final]独特的城市

对于每个点,它的答案最大就是与它距离最远的点的距离。

而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案。

所以我们需要找到对于每个点$u$距离它最远的点及最小的距离$x$满足距离$u$的距离大于等于$x$的点都只有一个。

那么怎么找距离每个点最远的点?

这个点自然就是树的直径的一个端点了!

我们将树的直径先找到,然后讨论一下对于每个点,有哪些点可能会被计入答案:

如图所示,我们以点$x$为例,假设它距离直径两端点中的$S$较近($y$为$x$距离直径上最近的点),设$dis$代表两点距离:

对于$y$左边点所有点,显然$S$与$y$的距离最远,但$dis(S,y)<dis(T,y)$,所以$y$左边的所有点都不会被计入答案。

对于在$x$子树中的点,他们与$x$的距离要小于$dis(y,T)$,也就小于$dis(x,T)$,所以不会被计入答案。

对于在$y$子树中但不在$x$子树中的点(例如$b$),因为$dis(y,b)\le dis(y,S)$,所以$dis(b,d)<dis(S,d)$,不会被计入答案。

对于$y$与$T$之间的点的子树中的点(例如$c$),显然$dis(y,c)\le dis(y,T)$,所以这类点不会被计入答案。

那么综上所述对于靠近$S$的点,只有$x$到$T$之间的点才有可能被计入答案,对于靠近$T$的点同理。

所以我们只需要分别以$S$和$T$为根遍历整棵树,用一个单调栈保存每个点到根的这条链上能被计入答案的点即可。

求不同权值个数,再开一个桶记录栈中每种权值的个数,每次进栈或弹栈时对应加减。

因为答案与深度有关,我们将原树长链剖分。

对于每个点,当走重儿子时,求出所有轻儿子的子树中的最长链长度$len$,将当前栈中与$x$距离小于等于$len$的点弹出;当遍历轻儿子时,将当前栈中与$x$距离小于等于$x$往下最长链长度的点弹出。

注意要在弹栈之后再把$x$压入栈中,而且遍历每个儿子前都要重新将$x$压入栈中。

最后将以$S$为根时的答案与以$T$为根时的答案取最大值即可。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int head[200010];
int to[400010];
int dep[200010];
int next[400010];
int mx[200010];
int son[200010];
int st[200010];
int top;
int tot;
int S,T;
int res;
int ans[200010];
int n,m;
int x,y;
int col[200010];
int cnt[200010];
void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void pop()
{
cnt[col[st[top]]]--;
res-=(cnt[col[st[top]]]==0);
top--;
}
void push(int x)
{
st[++top]=x;
cnt[col[x]]++;
res+=(cnt[col[x]]==1);
}
void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dfs(to[i],x);
}
}
}
void dfs1(int x,int fa)
{
son[x]=0;
mx[x]=0;
dep[x]=dep[fa]+1;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa)
{
dfs1(to[i],x);
if(mx[to[i]]>mx[son[x]])
{
son[x]=to[i];
}
}
}
mx[x]=mx[son[x]]+1;
}
void dfs2(int x,int fa)
{
if(!son[x])
{
ans[x]=max(ans[x],res);
return ;
}
int len=0;
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa&&to[i]!=son[x])
{
len=max(len,mx[to[i]]);
}
}
while(top&&dep[st[top]]>=dep[x]-len)
{
pop();
}
push(x);
dfs2(son[x],x);
for(int i=head[x];i;i=next[i])
{
if(to[i]!=fa&&to[i]!=son[x])
{
while(top&&dep[st[top]]>=dep[x]-mx[son[x]])
{
pop();
}
push(x);
dfs2(to[i],x);
}
}
while(top&&dep[st[top]]>=dep[x]-mx[son[x]])
{
pop();
}
ans[x]=max(ans[x],res);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&col[i]);
}
dfs(1,0);
for(int i=1;i<=n;i++)
{
S=dep[i]>dep[S]?i:S;
}
dfs(S,0);
for(int i=1;i<=n;i++)
{
T=dep[i]>dep[T]?i:T;
}
dfs1(S,0);
dfs2(S,0);
dfs1(T,0);
dfs2(T,0);
for(int i=1;i<=n;i++)
{
printf("%d\n",ans[i]);
}
}

[LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分的更多相关文章

  1. 题解 [JOI 2019 Final] 独特的城市

    题面 解析 首先有一个结论, 对一个点\(x\)有贡献的城市 肯定在它到离它较远的直径的端点的链上. 假设离它较远的端点是\(S\), 如果有一个点\(u\)不在\(x\)到\(S\)的链上, 却对\ ...

  2. LOJ3053 十二省联考2019 希望 容斥、树形DP、长链剖分

    传送门 官方题解其实讲的挺清楚了,就是锅有点多-- 一些有启发性的部分分 L=N 一个经典(反正我是不会)的容斥:最后的答案=对于每个点能够以它作为集合点的方案数-对于每条边能够以其两个端点作为集合点 ...

  3. 2019.01.08 bzoj4543: [POI2014]Hotel加强版(长链剖分+dp)

    传送门 代码: 长链剖分好题. 题意:给你一棵树,问树上选三个互不相同的节点,使得这个三个点两两之间距离相等的方案数. 思路: 先考虑dpdpdp. fi,jf_{i,j}fi,j​表示iii子树中离 ...

  4. 2019.01.08 codeforces 1009F. Dominant Indices(长链剖分)

    传送门 长链剖分模板题. 题意:给出一棵树,设fi,jf_{i,j}fi,j​表示iii的子树中距离点iii距离为jjj的点的个数,现在对于每个点iii要求出使得fif_ifi​取得最大值的那个jjj ...

  5. 2019.01.06 vijos lxhgww的奇思妙想(长链剖分)

    传送门 长链剖分模板题. 题意简述:允许O(nlogn)O(nlog_n)O(nlogn​)预处理,让你支持O(1)O(1)O(1)查找任意一个点的kkk级祖先. 思路:因为要O(1)O(1)O(1) ...

  6. 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)

    LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...

  7. loj 3014「JOI 2019 Final」独特的城市

    loj 我本来是直接口胡了一个意思一样的做法的,但是因为觉得有点假+实现要用并查集(?)就卡了好一会儿... 对于一个点\(x\)来说,独特的点一定在它的最长链上,如果有独特的点不在最长链上,那么最长 ...

  8. JOI 2019 Final合集

    JOI 2019 Final 合集 #3010. 「JOI 2019 Final」勇者比太郎 其实如果读懂题了就是水题了 题目就是让你求满足条件的\(JOI​\),使得\(O​\)在\(J​\)同行的 ...

  9. 2019.01.21 bzoj1758: [Wc2010]重建计划(01分数规划+长链剖分+线段树)

    传送门 长链剖分好题. 题意简述:给一棵树,问边数在[L,R][L,R][L,R]之间的路径权值和与边数之比的最大值. 思路: 用脚指头想都知道要01分数规划. 考虑怎么checkcheckcheck ...

随机推荐

  1. WebServeice 动态代理类

    1, webservice是什么? 是一个平台独立的,低耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述.发布.发现.协调和配置这些应用程序 ...

  2. MyBatis之整合Spring

    MyBatis之整合Spring 整合思路: 1.SqlSessionFactory对象应该放到spring容器中作为单例存在 2.传统dao的开发方式中,应该从spring容器中获得sqlSessi ...

  3. .net工作流引擎ccflow新增支持PostgreSQL数据库的功能的发布说明

    关键字: 驰骋工作流程快速开发平台 工作流程管理系统 工作流引擎 asp.net工作流引擎  java工作流引擎. 各位驰骋工作流引擎爱好着,经过驰骋公司与正元公司的共同努力,ccflow支持Post ...

  4. netstat -an查看到大量的TIME_WAIT状态的解决办法

    netstat下time_wait状态的tcp连接: 1.这是一种处于连接完全关闭状态前的状态: 2.通常要等上4分钟(windows server)的时间才能完全关闭: 3.这种状态下的tcp连接占 ...

  5. java笔记---- 获取外网(公网)的ip地址

    import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import ...

  6. Asp.Net中virtual、override理解

    virtual关键字用于指定属性或方法在派生类中重写.默认情况下,派生类从其基类继承属性和方法,如果继承的属性或方法需要在派生类中有不同的行为,则可以重写它,即可以在派生类中定义该属性或方法的新实现, ...

  7. 【不定期更新】FPGA/IC岗位常见笔试面试题总结(基础知识)

    1 数字IC(ASIC)设计流程: IC设计分为前端和后端.前端设计主要将HDL语言-->网表,后端设计是网表-->芯片版图. 前端主要有需求分析与架构设计.RTL设计.仿真验证.逻辑综合 ...

  8. java拦截器(interceptor)

    1.声明式 (1)注解,使用Aspect的@Aspect (2)实现HandlerInterceptor /** * 拦截请求 * * @author Administrator * */ @Comp ...

  9. 金蝶K3外购入库单单价取数规则调整

    涉及界面: 问题:财务抱怨外购入库单价格取错,单价多除了一次税率 例如,采购单里面注明了价格是不含税15.3256 结果在外购入库单里面,又自做主张除以税率17%,把采购成本搞成了13.0988, 咨 ...

  10. react-router(v4)

    概要 开发单页应用, 首先绕不开的内容就是路由, react router v4 版本是最新的版本. 和之前的版本相比, 成熟了很多, 也简单了很多, 使用起来更加方便. 核心 component r ...