P3398 仓鼠找sugar
题目描述
小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n。地下洞穴是一个树形结构。这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c)到图书馆(d)。他们都会走最短路径。现在小仓鼠希望知道,有没有可能在某个地方,可以碰到他的基友?
小仓鼠那么弱,还要天天被zzq大爷虐,请你快来救救他吧!
输入格式
第一行两个正整数n和q,表示这棵树节点的个数和询问的个数。
接下来n-1行,每行两个正整数u和v,表示节点u到节点v之间有一条边。
接下来q行,每行四个正整数a、b、c和d,表示节点编号,也就是一次询问,其意义如上。
输出格式
对于每个询问,如果有公共点,输出大写字母“Y”;否则输出“N”。
输入输出样例
输入 #1复制
5 5
2 5
4 2
1 3
1 4
5 1 5 1
2 2 1 4
4 1 3 4
3 1 1 5
3 5 1 4
输出 #1复制
Y
N
Y
Y
Y
说明/提示
本题时限1s,内存限制128M,因新评测机速度较为接近NOIP评测机速度,请注意常数问题带来的影响。
20%的数据 n<=200,q<=200
40%的数据 n<=2000,q<=2000
70%的数据 n<=50000,q<=50000
100%的数据 n<=100000,q<=100000
思路:
对于树上的两段路而言,若有重合,则这两段路的四个焦点的各自的lca的lca必定为这两个中的其中一个。
即:
节点“1” && “2”的lca必定为节点“1” || “2”
但也会有一个bug…………
如图:
就会发现挂了…………qwq
继续推…………
然后又会有一个发现,若lca ( d,c )在a ~ lca ( a,b ) || b ~ lca ( a,b )上
则说明可行…………但OJBK了么…………qwq…………并没有…………
还可能是lca ( a,b)在c ~ lca ( c,d ) || d ~ lca ( c,d )上
则要反过来………………
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <queue>
#include <cmath>
#define LL long long
using namespace std;
const int N=5*1e5+100,M=1001;
int n,m,u,v,a,b,c,d,f[N][30],dis[N],cnt[N],high[N];
vector < int > q[N];
void dfs ( int rt,int fa,int h )
{
f[rt][0]=fa;
high[rt]=h++;
int len=q[rt].size ( );
for ( int i=0;i<len;i++ )
{
int to=q[rt][i];
if ( to!=fa ) dfs ( to,rt,h );
}
}
int lca ( int x,int y )
{
if ( high[x]>high[y] ) swap ( x,y );
int c=high[y]-high[x],k=21,m=1<<k;
while ( c )
{
if ( c>=m ) y=f[y][k],c-=m;
m/=2,k--;
}
if ( x==y ) return x;
k=19;
while ( k>=0 ) { if ( f[x][k]!=f[y][k] ) x=f[x][k],y=f[y][k];k--; }
return f[x][0];
}
int main ( )
{
scanf ( "%d %d",&n,&m );
for ( int i=1;i<n;i++ )
{
scanf ( "%d %d",&u,&v );
q[u].push_back ( v ),q[v].push_back (u);
}
dfs ( 1,0,1 );
for ( int j=1;j<=21;j++ ) for ( int i=1;i<=n;i++ ) f[i][j]=f[f[i][j-1]][j-1];
while ( m-- )
{
scanf ( "%d %d %d %d",&a,&b,&c,&d );
int ab=lca ( a,b ),cd=lca ( c,d ),ab_cd=lca ( ab,cd );
if ( ab_cd==ab || ab_cd==cd ) //大前提
{
if ( high[ab]>high[cd] ) swap ( ab,cd ),swap ( a,c ),swap ( b,d ); //交换
int cd_a=lca ( cd,a ),cd_b=lca ( cd,b );
if ( cd_a==cd || cd_b==cd ) printf ( "Y\n" ); //在路径上
else printf ( "N\n" );
}
else printf ( "N\n" );
}
return 0;
}