洛谷P3398 仓鼠找sugar-LCA倍增/树剖

题意

一颗多叉树,给四个点,求有无公共点。

基本思路

倍增LCA,若$dep(lca(a,b))>dep(lca(cd))$,若有公共点,则$lca(lca(a,b),c)==lca(a,b)$或$lca(lca(a,b),d)==lca(a,b)$,反之亦然

倍增做法

  1 #include<bits/stdc++.h>
  2 #define FOR(i,a,b) for(int i=a;i<b;i++)
  3 #define FOR2(i,a,b) for(int i=a;i<=b;i++)
  4 #define ll long long
  5 #define INF  0x7f7f7f7f;
  6 #define MAXN 200010
  7 #define MOD 10007
  8 #define MAXJUMP 22 
  9 using namespace std;
 10 typedef struct{
 11     int from,to,next;
 12 }EDGE;EDGE edges[MAXN]; 
 13 int a,b,c,d,n,m,s,ed=0,head[MAXN]; 
 14 int jump[MAXN][30],dep[MAXN];
 15 inline int read()
 16 {
 17     char ch=getchar();
 18     int x=0,f=1;
 19     while((ch>'9'||ch<'0')&&ch!='-')
 20         ch=getchar();
 21     if(ch=='-')
 22     {
 23         f=-1;
 24         ch=getchar();
 25     }
 26     while('0'<=ch&&ch<='9')
 27     {
 28         x=x*10+ch-'0';
 29         ch=getchar();
 30     }
 31     return x*f;
 32 }
 33 inline void put(int x)
 34 {
 35     if(x==0)
 36     {
 37         putchar('0');
 38         putchar('
');
 39         return;
 40     }
 41     int num=0;
 42     char c[25];
 43     while(x)
 44     {
 45         c[++num]=(x%10)+48;
 46         x/=10;
 47     }
 48     while(num)
 49         putchar(c[num--]);
 50     putchar('
');
 51     return ;
 52 }
 53 inline int log2(int x)
 54 {
 55     int k=0;while(x>1)x=x>>1,k++;return k;
 56 }
 57 inline void add(int a,int b)
 58 {
 59     edges[++ed].from=a;
 60     edges[ed].to=b;
 61     edges[ed].next=head[a];
 62     head[a]=ed;
 63     return;
 64 } 
 65 
 66 void dfs(int cur,int pre)
 67 {
 68     jump[cur][0]=pre;
 69     dep[cur]=dep[pre]+1;
 70     for(int i=1;i<=MAXJUMP;i++)
 71     {//记录跳点 
 72         jump[cur][i]=jump[jump[cur][i-1]][i-1];
 73     }
 74     for(int i=head[cur];i;i=edges[i].next)
 75     {
 76         if(edges[i].to==pre)continue;
 77         dfs(edges[i].to,cur);
 78     } 
 79 }
 80 int lca(int a,int b)
 81 {
 82     if(dep[a]<dep[b])
 83     {
 84         swap(a,b);
 85     }
 86     for(int i=MAXJUMP;i>=0;i--)
 87     {
 88         if((1<<i)<=dep[a]-dep[b])
 89         {
 90             a=jump[a][i];
 91         }
 92     }
 93     if(a==b)
 94         return a;
 95     for(int i=MAXJUMP;i>=0;i--)
 96     {
 97         if(jump[a][i]!=jump[b][i])
 98             a=jump[a][i],b=jump[b][i];
 99     }
100     return jump[a][0];//返回共同父节点     
101 }
102 vector<int>q;
103 int main()
104 {//倍增 
105     n=read();m=read();
106     FOR(i,1,n)
107     {
108         a=read();b=read();
109         add(a,b);add(b,a);q.push_back(b);
110     }
111     sort(q.begin(),q.end());
112     FOR(i,0,q.size())
113     {
114         if(i+1!=q[i])
115         {//确定起点 
116             s=i+1;break;
117         }
118     }
119     
120     dfs(s,0);
121     FOR(i,0,m)
122     {
123         a=read();b=read();c=read();d=read();
124         int ab=lca(a,b);//cout<<ab<<" ";
125         int cd=lca(c,d);//cout<<cd<<" ";
126         
127         if(dep[ab]>dep[cd])
128         {
129             if(ab==lca(ab,c)||ab==lca(ab,d)) cout<<"Y"<<endl;
130             else cout<<"N"<<endl;
131         }
132         else {
133             if(cd==lca(cd,a)||cd==lca(cd,b)) cout<<"Y"<<endl;
134             else cout<<"N"<<endl;
135         }
136         
137     }
138     return 0;
139 }
View Code

树剖做法

原文地址:https://www.cnblogs.com/tldr/p/11296868.html