洛谷 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”。

我们画两棵树YY一下啊,如果这两条路径在树上有交点的话呢,那么这两条路径的长度之和,必然大于等于两个起点和两个终点的路径和,先用spfa处理出距离,然后树剖处理询问
QWQ

#include 
#include 
#include 
#include 
using namespace std;
const int M=200005;
const int N=100004;
int n,q,x,y,xx,yy,tot,head[M],nex[M],to[M],dis[M];
bool vis[M];
struct tree{
    int son,fa,top,sz,s,e,dep;
}tr[N];
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add(int a,int b){
	++tot;
	nex[tot]=head[a];
	head[a]=tot;
	to[tot]=b;
}
inline void spfa(int x){
	queue<int> q;
	q.push(x);
	for(int i=1;i<=n;i++) dis[i]=2000000000;
	vis[x]=1;
	dis[x]=0;
	while(!q.empty()){
	   int dmf=q.front();
	   q.pop();
	   for(int i=head[dmf];i;i=nex[i]){
	   	   int zhn=to[i];
	   	   if(dis[zhn]>dis[dmf]+1){
	   	        dis[zhn]=dis[dmf]+1;
				if(!vis[zhn]){
					vis[zhn]=1;
					q.push(zhn);
				}	
		   }
	   }
	   vis[dmf]=0;
	} 
}
void dfs1(int u){
    tr[u].sz=1;
    for(int i=head[u];i;i=nex[i]){
        if(to[i]!=tr[u].fa){
            tr[to[i]].fa=u;
            tr[to[i]].dep=tr[u].dep+1;
            dfs1(to[i]);
            tr[u].sz+=tr[to[i]].sz;
            if(tr[to[i]].sz>tr[tr[u].son].sz)
              tr[u].son=to[i];
        }
    }
}
void dfs2(int u,int top){
    tr[u].top=top;
    if(tr[u].son){
        dfs2(tr[u].son,top);
        for(int i=head[u];i;i=nex[i])
        if(to[i]!=tr[u].fa&&to[i]!=tr[u].son)
        dfs2(to[i],to[i]);
    }
}
inline int lca(int x,int y){
    int f1=tr[x].top;
    int f2=tr[y].top;
    while(f1!=f2){
        if(tr[f1].dep<tr[f2].dep){
            swap(f1,f2);
            swap(x,y);
        }
        x=tr[f1].fa;
        f1=tr[x].top;
    }
    if(tr[x].dep<tr[y].dep) return x;
    else return y;
}
inline int cal(int x,int y){//求两点之间的距离 
	int fa=lca(x,y);
	return dis[x]+dis[y]-2*dis[fa];
}
int main(){
	n=read();q=read();
	for(int i=1;i<n;i++){
		x=read();y=read();
		add(x,y);
		add(y,x);
	}
	spfa(1);
	dfs1(1); 
	dfs2(1,1);
	for(int i=1;i<=q;i++){
		x=read();y=read();
		xx=read();yy=read();
		if(cal(x,y)+cal(xx,yy)>=cal(x,xx)+cal(y,yy)) puts("Y");
		else puts("N"); 
	}
	return 0;
} 

你可能感兴趣的:(spfa,树链剖分)