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;
    }
}
复制代码

 

posted @   liyishui  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示