Codeforces 题面传送门 & 洛谷题面传送门

树上数据结构大杂烩(?)

首先考虑什么样的点能够在所有路径的 \(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(树的直径)的更多相关文章

  1. codeforces 14D(搜索+求树的直径模板)

    D. Two Paths time limit per test 2 seconds memory limit per test 64 megabytes input standard input o ...

  2. Codeforces 379F New Year Tree 树的直径的性质推理

    New Year Tree 我们假设当前的直径两端为A, B, 那么现在加入v的两个儿子x, y. 求直径的话我们可以第一次dfs找到最远点这个点必定为直径上的点, 然而用这个点第二次dfs找到最远点 ...

  3. codeforces GYM 100114 J. Computer Network 无相图缩点+树的直径

    题目链接: http://codeforces.com/gym/100114 Description The computer network of “Plunder & Flee Inc.” ...

  4. codeforces GYM 100114 J. Computer Network tarjan 树的直径 缩点

    J. Computer Network Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Des ...

  5. Codeforces 592D - Super M - [树的直径][DFS]

    Time limit 2000 ms Memory limit 262144 kB Source Codeforces Round #328 (Div. 2) Ari the monster is n ...

  6. 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 ...

  7. Codeforces 455C Civilization:树的直径 + 并查集【合并树后直径最小】

    题目链接:http://codeforces.com/problemset/problem/455/C 题意: 给你一个森林,n个点,m条边. 然后有t个操作.共有两种操作: (1)1 x: 输出节点 ...

  8. Codeforces 337D Book of Evil:树的直径【结论】

    题目链接:http://codeforces.com/problemset/problem/337/D 题意: 给你一棵树,n个节点. 如果一个节点处放着“罪恶之书”,那么它会影响周围距离不超过d的所 ...

  9. CodeForces - 592D: Super M(虚树+树的直径)

    Ari the monster is not an ordinary monster. She is the hidden identity of Super M, the Byteforces’ s ...

随机推荐

  1. 【UE4 设计模式】组件模式 Components Pattern

    概述 描述 在单一实体跨越了多个领域时,为了保持领域之间相互解耦,可以将每部分代码放入各自的组件类中,将实体简化为组件的容器. 套路 参考 UE4中的 Componet 组件使用方式 使用场景 有一个 ...

  2. SpringMvc 中 FrameworkServlet 覆盖 service 的有点。

    @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws Se ...

  3. 设置nginx进程可打开最大的文件数

    涉及到的nginx配置参数: worker_processes: 表示操作系统启动多少个工作进程在运行,一般这个参数设置成CPU核数的倍数 worker_connections:表示nginx的工作进 ...

  4. 在Vue前端项目中,附件展示的自定义组件开发

    在Vue前端界面中,自定义组件很重要,也很方便,我们一般是把一些通用的界面模块进行拆分,创建自己的自定义组件,这样操作可以大大降低页面的代码量,以及提高功能模块的开发效率,本篇随笔继续介绍在Vue&a ...

  5. Noip模拟69 2021.10.5

    考场拼命$yy$高精度结果没学好$for$循环痛失$50pts$,当场枯死 以后一定打对拍,要不考后会... T1 石子游戏 首先要知道典型的$NIM$博弈,就是说如果所有堆石子个数的异或和为$0$则 ...

  6. USB线上/串口/I2C引脚串联电阻的作用

    对引脚的保护. 第一是阻抗匹配.因为信号源的阻抗很低,跟信号线之间阻抗不匹配,串上一个电阻后,可改善匹配情况,以减少反射,避免振荡等. 第二是可以减少信号边沿的陡峭程度,从而减少高频噪声以及过冲等.因 ...

  7. iPhone SE切换颜色特效

    Apple 网站的特效, iPhone SE 共有黑.白.红三种颜色,在卷动页面的时候会逐步替换,看起来效果非常时尚,在此供上代码学习. <!DOCTYPE html> <html& ...

  8. 小白自制Linux开发板 十. NES游戏玩起来

    本篇基于我们制作的Debian文件系统而展开,而且我们这会玩一些高级的操作方式--用我们的小电脑进行程序编译.   所以本篇操作全部都在我们个的开发板上完成.   1. 开发环境搭建 首先安装gcc, ...

  9. cf12D Ball(MAP,排序,贪心思想)

    题意: N位女士一起聚在一个舞厅.每位女士有三个特征值B,I,R.分别代表美貌,智慧,富有. 对于一位女士而言,如果存在一个女士的B,I,R都分别大于她自己的B,I,R.则她自己会自杀. 统计总共有多 ...

  10. coreseek使用心得

    基本使用方法: D:\coreseek-4.1\bin\searchd -c D:\coreseek-4.1\etc\article.conf --stop 停止服务 D:\coreseek-4.1\ ...