Codeforces 1464F - My Beautiful Madness(树的直径)
树上数据结构大杂烩(?)
首先考虑什么样的点能够在所有路径的 \(d\) 邻居的交集内。显然如果一个点在一条路径的 \(d\) 邻居内则必须有该点到这条路径上所有点中最近的点的距离 \(\le d\),因此一个点在所有路径 \(d\) 邻居的交集内,当且仅当对于所有路径,该点到该路径上点距离的最小值的最大值 \(\le d\),我们即需判定是否存在这样的点。
直接维护显然不容易,不过我们思考这样一个问题:是否存在一个点,满足只要所有路径的 \(d\) 邻居的交集非空,该点就必然在这些路径 \(d\) 邻居的交集内?答案是肯定的,我们考虑以 \(1\) 为根对整棵树进行一遍 DFS,那么所有路径的两个端点的 LCA 中,深度最大的那个的 \(d\) 级祖先即为符合要求的点。具体证明大概就,设 \(u\) 为深度最大的祖先的 \(d\) 级祖先,那么:
- 对于两个端点都在 \(u\) 子树内的路径,由于 \(u\) 到这样的路径中任意一点距离的最小值为 \(u\) 到路径两端点的 LCA 的距离,而 \(u\) 到 LCA 最深的路径的距离不过 \(d\),因此对于这样的路径一定是符合条件的,同时说明不在 \(u\) 子树内的点一定不符合要求,因为它到 LCA 深度最大的路径的最小距离肯定 \(>d\)
- 对于一个端点在 \(u\) 子树内的点,另一个端点不在的路径,显然这样的路径会经过 \(u\),自然符合条件
- 对于两个端点都不在 \(u\) 子树内的点,由于所有符合要求的点都在 \(u\) 子树内,所以 \(u\) 是 \(u\) 子树内到这样的路径距离最小的点,也就是说 \(u\) 是最有可能符合要求的点。
显然这个 \(u\) 可以通过 set
之类的东西维护,于是现在问题转化为如何判定一个点是否到所有路径距离都 \(\le d\)。
首先考虑 \(u\) 的 \(d\) 级祖先 \(v\),如果存在一个路径满足其与 \(v\) 的子树无交集,那么显然 \(u\) 到这样的路径距离 \(>d\),也就不符合要求,这个可以通过加入一条路径 \((u,v)\) 时对 \(1\to u\) 路径上所有点 \(+1\),\(1\to v\) 路径上所有点 \(+1\),\(1\to\text{LCA}(u,v)\) 路径上所有点都 \(-1\),然后判断 \(v\) 的权值是否等于当前路径条数即可。其次还有一个必要条件就是 \(u\) 到所有 \(\text{LCA}\) 在 \(v\) 子树内的点的距离的 \(\text{LCA}\le d\)(当然如果路径的两个端点一个在 \(u\) 子树内,一个不在 \(u\) 子树内,那么 \(u\) 到这样的路径的最小距离并不是 \(u\) 到它们 LCA 的距离,而是 \(0\),不过由于显然 \(u\) 到它们 LCA 的距离 \(\le d\),因此这个转化并不影响)根据直径那套理论,如果我们称 \(v\) 子树内一个点为关键点,当且仅当它是某条路径的 LCA,那么 \(v\) 子树内距离 \(u\) 最远的关键点就是 \(u\) 子树内所有关键点组成的直径之一,这个可以通过 DFS 序+树的直径的合并方式维护。不难发现一个点 \(u\) 符合条件的充要条件就这么多,于是这题就做完了。
时间复杂度 \((n+q)\log n\)。
orz 线段树分治解法……
const int MAXN=2e5;
const int LOG_N=19;
int n,qu,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int dfn_eu[MAXN+5],tim_eu=0,dep[MAXN+5],dfn[MAXN+5],ed[MAXN+5],tim=0;
int fa[MAXN+5][LOG_N+2];
pii st[MAXN*2+5][LOG_N+2];
void dfs(int x,int f){
fa[x][0]=f;dfn[x]=++tim;
st[dfn_eu[x]=++tim_eu][0]=mp(dep[x],x);
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f) continue;
dep[y]=dep[x]+1;dfs(y,x);
st[dfn_eu[x]=++tim_eu][0]=mp(dep[x],x);
} ed[x]=tim;
}
pii query_st(int l,int r){
int k=31-__builtin_clz(r-l+1);
return min(st[l][k],st[r-(1<<k)+1][k]);
}
int getlca(int x,int y){
x=dfn_eu[x];y=dfn_eu[y];if(x>y) swap(x,y);
return query_st(x,y).se;
}
int get_kanc(int x,int k){
for(int i=LOG_N;~i;i--) if(k>>i&1) x=fa[x][i];
return max(x,1);
}
int getdist(int x,int y){return dep[x]+dep[y]-(dep[getlca(x,y)]<<1);}
void st_init(){
dfs(1,0);
for(int i=1;i<=LOG_N;i++) for(int j=1;j+(1<<i)-1<=n*2;j++)
st[j][i]=min(st[j][i-1],st[j+(1<<i-1)][i-1]);
for(int i=1;i<=LOG_N;i++) for(int j=1;j<=n;j++) fa[j][i]=fa[fa[j][i-1]][i-1];
}
struct fenwick_tree{
int t[MAXN+5];
void add(int x,int v){for(int i=x;i<=n;i+=(i&(-i))) t[i]+=v;}
int query(int x){int ret=0;for(int i=x;i;i&=(i-1)) ret+=t[i];return ret;}
int query_range(int l,int r){return query(r)-query(l-1);}
} t;
int cnt_pth=0;
int qry_sub(int x){return t.query_range(dfn[x],ed[x]);}
void add_pth(int u,int v,int x){
t.add(dfn[u],x);t.add(dfn[v],x);
t.add(dfn[getlca(u,v)],-x);
}
multiset<pii> lca;
struct dat{
int u,v;
dat(int _u=0,int _v=0):u(_u),v(_v){}
dat operator +(const dat &rhs){
if(!u) return rhs;
if(!rhs.u) return *this;
vector<pair<int,pii> > dists;
dists.pb(mp(getdist(u,rhs.u),mp(u,rhs.u)));
dists.pb(mp(getdist(u,rhs.v),mp(u,rhs.v)));
dists.pb(mp(getdist(v,rhs.u),mp(v,rhs.u)));
dists.pb(mp(getdist(v,rhs.v),mp(v,rhs.v)));
dists.pb(mp(getdist(u,v),mp(u,v)));
dists.pb(mp(getdist(rhs.u,rhs.v),mp(rhs.u,rhs.v)));
sort(dists.begin(),dists.end());
return dat(dists[5].se.fi,dists[5].se.se);
}
};
struct node{int l,r;dat v;} s[MAXN*4+5];
void pushup(int k){s[k].v=s[k<<1].v+s[k<<1|1].v;}
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;if(l==r) return;int mid=l+r>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void modify(int k,int p,dat v){
if(s[k].l==s[k].r) return s[k].v=v,void();
int mid=s[k].l+s[k].r>>1;
(p<=mid)?modify(k<<1,p,v):modify(k<<1|1,p,v);
pushup(k);
}
dat query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return s[k].v;
int mid=s[k].l+s[k].r>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
}
int cnt[MAXN+5],pth_cnt=0;
void ins_pth(int u,int v){
pth_cnt++;add_pth(u,v,1);int lc=getlca(u,v);
cnt[lc]++;lca.insert(mp(dep[lc],lc));
if(cnt[lc]==1) modify(1,dfn[lc],dat(lc,lc));
}
void del_pth(int u,int v){
pth_cnt--;add_pth(u,v,-1);int lc=getlca(u,v);
cnt[lc]--;lca.erase(lca.find(mp(dep[lc],lc)));
if(cnt[lc]==0) modify(1,dfn[lc],dat(0,0));
}
bool check(int d){
pii pp=*lca.rbegin();
int u=get_kanc(pp.se,d),v=get_kanc(u,d);
if(qry_sub(v)!=pth_cnt) return 0;
dat dt=query(1,dfn[v],ed[v]);
if(max(getdist(u,dt.u),getdist(u,dt.v))>d) return 0;
return 1;
}
int main(){
scanf("%d%d",&n,&qu);
for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
st_init();build(1,1,n);
while(qu--){
int opt;scanf("%d",&opt);
if(opt==1){
int u,v;scanf("%d%d",&u,&v);
ins_pth(u,v);
} else if(opt==2){
int u,v;scanf("%d%d",&u,&v);
del_pth(u,v);
} else {
int d;scanf("%d",&d);
printf("%s\n",(check(d))?"Yes":"No");
}
}
return 0;
}
Codeforces 1464F - My Beautiful Madness(树的直径)的更多相关文章
- codeforces 14D(搜索+求树的直径模板)
D. Two Paths time limit per test 2 seconds memory limit per test 64 megabytes input standard input o ...
- Codeforces 379F New Year Tree 树的直径的性质推理
New Year Tree 我们假设当前的直径两端为A, B, 那么现在加入v的两个儿子x, y. 求直径的话我们可以第一次dfs找到最远点这个点必定为直径上的点, 然而用这个点第二次dfs找到最远点 ...
- codeforces GYM 100114 J. Computer Network 无相图缩点+树的直径
题目链接: http://codeforces.com/gym/100114 Description The computer network of “Plunder & Flee Inc.” ...
- codeforces GYM 100114 J. Computer Network tarjan 树的直径 缩点
J. Computer Network Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Des ...
- Codeforces 592D - Super M - [树的直径][DFS]
Time limit 2000 ms Memory limit 262144 kB Source Codeforces Round #328 (Div. 2) Ari the monster is n ...
- Codeforces Beta Round #14 (Div. 2) D. Two Paths 树的直径
题目链接: http://codeforces.com/contest/14/problem/D D. Two Paths time limit per test2 secondsmemory lim ...
- Codeforces 455C Civilization:树的直径 + 并查集【合并树后直径最小】
题目链接:http://codeforces.com/problemset/problem/455/C 题意: 给你一个森林,n个点,m条边. 然后有t个操作.共有两种操作: (1)1 x: 输出节点 ...
- Codeforces 337D Book of Evil:树的直径【结论】
题目链接:http://codeforces.com/problemset/problem/337/D 题意: 给你一棵树,n个节点. 如果一个节点处放着“罪恶之书”,那么它会影响周围距离不超过d的所 ...
- CodeForces - 592D: Super M(虚树+树的直径)
Ari the monster is not an ordinary monster. She is the hidden identity of Super M, the Byteforces’ s ...
随机推荐
- 【UE4】GAMES101 图形学作业0:矩阵初识
作业描述 给定一个点P=(2,1), 将该点绕原点先逆时针旋转45◦,再平移(1,2), 计算出变换后点的坐标(要求用齐次坐标进行计算). UE4 知识点 主要矩阵 FMatrix FBasisVec ...
- 240.搜索二维矩阵II
从左下角位置开始搜索 时间复杂度:O(行数+列数). 想法有点像二分法,大了往一个方向找,小了往另一个方向找.由于矩阵横向和纵向都是递增,如果从(0,0)位置开始找,往右和往下都是增大,因此不知道实际 ...
- spring social理解
现在互联网飞速发展,人们每天在互联网上冲浪,获取各种信息.各大网站为了方便用户的登录,提供了各式各样的社交登录,比如:QQ.微信和微博登录等.这些主流的社交登录大多是基于oauth协议进行实现,spr ...
- Docker制作能够ssh连接的镜像
本类文章只作为记录使用 命令操作: #拉取Centos 7 docker pull centos:7 #运行一个镜像 docker run -tdi --privileged centos:7 ini ...
- 预备知识-python核心用法常用数据分析库(上)
1.预备知识-python核心用法常用数据分析库(上) 目录 1.预备知识-python核心用法常用数据分析库(上) 概述 实验环境 任务一:环境安装与配置 [实验目标] [实验步骤] 任务二:Pan ...
- STM32中断编程三步曲教你弄会中断设置以及中断优先级设置
中断作为stm32中必不可少的一个功能,其重要性是不言而喻的因此把中断学习好是根本. 所以今天就来好好啃一下中断配置的知识,俗话说:磨刀不误砍柴工.问题是什么呢?项目中我用到了一个触摸键盘TTP229 ...
- 『学了就忘』Linux基础 — 13、Linux系统的分区和格式化
目录 1.Linux系统的分区 (1)磁盘分区定义 (2)两种分区表形式 (3)MBR分区类型 2.Linux系统的格式化 (1)格式化定义 (2)格式化说明 1.Linux系统的分区 (1)磁盘分区 ...
- linux cut
参考:Linux cut 命令详解_Linux_脚本之家 (jb51.net) 参考:cut命令_Linux cut 命令用法详解:连接文件并打印到标准输出设备上 (linuxde.net)
- 穿点最多的直线 牛客网 程序员面试金典 C++
穿点最多的直线 牛客网 程序员面试金典 C++ 题目描述 在二维平面上,有一些点,请找出经过点数最多的那条线. 给定一个点集vectorp和点集的大小n,没有两个点的横坐标相等的情况,请返回一个vec ...
- oracle静默安装完成后,重启数据库,错误ORA-01102: cannot mount database in EXCLUSIVE mode
静默安装oracle完成后,登录数据库激活用户,无法更改,提示未载入数据库,关闭后重启报错: 1.找到安装目录下的$ORACLE_HOME/dbs/ 目录下,查看当前使用lkORCL文件的用户(fus ...