题:https://codeforces.com/contest/1304/problem/E
题意:给定一颗树,边权为1,m次询问,每次询问给定x,y,a,b,k,问能否在原树上添加x到y的边,a到b的路径长度等于k,注意这里的点和边都是可以重复走的;
分析:注意到点边可以重复走,我们就可以推出一个条件就是a、b之间的长度len要满足>=k;
其次当路长大于k时,我们就要判断len和k是否同奇偶,因为要到达长度len要被分为:len=k+2*i(i>=0),否则无法构造出这么一条路径
然后添加x-y造成的路径选择,有分为最简单的3种
1、直接走a,b;
2、走a-x-y-b;
3、走a-y-x-b;
然后树上路径就用倍增lca模板即可求俩点间距离

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<cmath> using namespace std; #define pb push_back const int M=2e5+4; const int N=20; struct node{ int v,w; node(int vv=0,int ww=0):v(vv),w(ww){} }; vector<node>e[M]; int s,grand[M][N],dis[M][N],deep[M],root,n; void dfs(int u){ for(int i=1;i<=s;i++){ grand[u][i]=grand[grand[u][i-1]][i-1]; dis[u][i]=dis[u][i-1]+dis[grand[u][i-1]][i-1]; if(!grand[u][i]) break; } for(int i=0;i<e[u].size();i++){ int v=e[u][i].v; if(v!=grand[u][0]){ grand[v][0]=u; deep[v]=deep[u]+1; dis[v][0]=e[u][i].w; dfs(v); } // cout<<"!!"<<endl; } } void init(){ s=floor(log(1.0*n)/log(2.0)); deep[0]=-1; dfs(root); } int LCA(int a,int b){ if(deep[a]>deep[b]) swap(a,b); int ans=0; for(int i=s;i>=0;i--){ if(deep[b]>deep[a]&&deep[a]<=deep[grand[b][i]]) ans+=dis[b][i],b=grand[b][i]; } for(int i=s;i>=0;i--) if(grand[a][i]!=grand[b][i]) ans+=dis[a][i]+dis[b][i],b=grand[b][i],a=grand[a][i]; if(a!=b) ans+=dis[a][0]+dis[b][0]; return ans; } bool check(int a,int b){ return b>=a&&(a%2)==(b%2); } int main(){ scanf("%d",&n); for(int v,u,i=1;i<n;i++){ scanf("%d%d",&u,&v); e[u].pb(node(v,1)); e[v].pb(node(u,1)); } root=1; init(); int m; scanf("%d",&m); while(m--){ int x,y,a,b,k; scanf("%d%d%d%d%d",&x,&y,&a,&b,&k); /// cout<<LCA(a,b)<<endl; if(check(LCA(a,b),k)||check(LCA(a,x)+1+LCA(y,b),k)||check(LCA(a,y)+1+LCA(x,b),k)) puts("YES"); else puts("NO"); } return 0; }