CF #805(div3) G2. Passable Paths (hard version) LCA+分类讨论
记录一下LCA的板子,hin久没打了就是说(LCA的板子左转去某谷找)
判断一个点集是不是都在同一条链上,考虑在同一条链上的会有什么特性:
for(int i=1;i<=k;i++) { if(p[i]==p1||p[i]==p2||p[i]==plca) continue; if(p1!=plca&&p2!=plca){ if(lca(p[i],p1)==p[i]&&lca(p[i],p2)==plca||lca(p[i],p2)==p[i]&&lca(p[i],p1)==plca) continue; ok=0; } else if(p1==plca||p2==plca){ if(p1==plca){ if(lca(p[i],plca)!=plca||lca(p[i],p2)!=p[i]) ok=0; } else { if(lca(p[i],plca)!=plca||lca(p[i],p1)!=p[i]) ok=0; } } }
#分类讨论写得可能有点乱,but还是蛮清楚的hhh
链有两种,一种是竖着的毛毛虫,一种是拆成两条毛毛虫摊开的
我们把两个端点记为p1和p2,plca记作p1和p2的最近公共祖先
如果是竖着的毛毛虫:
else if(p1==plca||p2==plca){ if(p1==plca){ if(lca(p[i],plca)!=plca||lca(p[i],p2)!=p[i]) ok=0; } else { if(lca(p[i],plca)!=plca||lca(p[i],p1)!=p[i]) ok=0; } }
以p1为plca为例子(plca是p1和p2的lca)
那么链条上的点,当且仅当:和p1的lca应该==p1,和p2的lca应该是这个点本身
p2是plca同理啦!
如果是摊开的毛毛虫:
if(p1!=plca&&p2!=plca)
{ if(lca(p[i],p1)==p[i]&&lca(p[i],p2)==plca||lca(p[i],p2)==p[i]&&lca(p[i],p1)==plca) continue; ok=0; }
画图可知只有两种情况:
这个点夹在p1和plca中间,或者夹在p2和plca中间
如果是夹在p1和plca中间,应该有
lca(p[i],p1)==p[i]&&lca(p[i],p2)==plca
另一种情况同理~
#include<bits/stdc++.h> using namespace std; const int maxn=500007; int cnt=0,head[maxn],fa[maxn][40],dep[maxn],lg[maxn],p[maxn]; struct lys{ int from,to,nex; }e[maxn*2]; void add(int from,int to){ cnt++; e[cnt].to=to;e[cnt].from=from; e[cnt].nex=head[from];head[from]=cnt; } void dfs(int now,int fath) { fa[now][0]=fath;dep[now]=dep[fath]+1; for(int i=1;i<=lg[dep[now]];i++) fa[now][i]=fa[fa[now][i-1]][i-1]; for(int i=head[now];i;i=e[i].nex) { if(e[i].to!=fath) dfs(e[i].to,now); } } int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); while(dep[x]>dep[y]) x=fa[x][lg[dep[x]-dep[y]]-1]; if(x==y) return x; for(int k=lg[dep[x]]-1;k>=0;k--) if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k];//you jump,I jump~ return fa[x][0]; } int n,m,k,q; bool cmp(int a,int b) { return dep[a]>dep[b]; } int main() { cin>>n; for(int i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<lg[i-1] == i); for(int i=1;i<n;i++) { int x,y; cin>>x>>y; add(x,y);add(y,x); } dfs(1,0); cin>>q; for(int QAQ=1;QAQ<=q;QAQ++) { cin>>k; for(int j=1;j<=k;j++) { cin>>p[j]; } sort(p+1,p+k+1,cmp); int p1=p[1],p2=p[k],plca; for(int i=1;i<=k;i++) { if(lca(p[i],p1)!=p[i]) { p2=p[i];break; } } plca=lca(p1,p2); //cout<<p1<<" "<<p2<<" "<<plca<<endl; int ok=1; for(int i=1;i<=k;i++) { if(p[i]==p1||p[i]==p2||p[i]==plca) continue; if(p1!=plca&&p2!=plca){ if(lca(p[i],p1)==p[i]&&lca(p[i],p2)==plca||lca(p[i],p2)==p[i]&&lca(p[i],p1)==plca) continue; ok=0; } else if(p1==plca||p2==plca){ if(p1==plca){ if(lca(p[i],plca)!=plca||lca(p[i],p2)!=p[i]) ok=0; } else { if(lca(p[i],plca)!=plca||lca(p[i],p1)!=p[i]) ok=0; } } } if(ok==0){ cout<<"NO"<<endl; } else cout<<"YES"<<endl; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)