题解 挖宝
MD 赛时写了一年只有 MLE 四十分
出来简单卡了一下空间就过了
正解是换根 DP
倍增处理 \(x\) 在路径上的情况
否则 \(x\) 与 \(a, b\) 路径上第一个在 \((a, b)\) 这条链上的点是可以知道的
那么离线换根 DP,对这个点子树内前 3 远的点,向上倍增即可
然而我选择了一个巨大难调写法
在路径上是容易的
否则分类讨论位置
令 lca 为 \(t\)
在 \((1, t)\) 路径上可以直接倍增
否则可以找到\(x\) 与 \(a, b\) 路径上第一个在 \((a, b)\) 这条链上的点,令为 \(k\)
发现对于一个 \(i\),可以用差分 dfs 求出其子树内不在某些儿子子树内的与其距离为 \(k\) 的点
具体地,dfs 时对每个深度维护要求这个深度的点的询问编号,进入某个被 ban 的子树时删掉,离开时加回去
然后发现当这个 \(x\) 离 \((a, b)\) 最近的点是 lca 而且它拐到了某个祖先的子树里就会变得尤其离谱
那么再离线一遍 dfs,DP 出每个点向上走,可以拐到祖先的其它儿子的子树里的最长链及在哪个祖先处取到
然后就转化为上面的问题了
挺好写的,也就 9.6k 而已
upd:原来这里直接长链剖分就可以避免一大车差分 dfs 了
复杂度 \(O(n\logn)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, q;
int head[N], ecnt;
struct edge{int to, next;}e[N<<1];
inline void add(int s, int t) {e[++ecnt]={t, head[s]}; head[s]=ecnt;}
// namespace force{
// int dep[N], fa[21][N], back[N], lg[N];
// void dfs(int u, int pa) {
// for (int i=1; i<21; ++i)
// if (dep[u]>=1<<i) fa[i][u]=fa[i-1][fa[i-1][u]];
// else break;
// for (int i=head[u],v; ~i; i=e[i].next) {
// v = e[i].to;
// if (v==pa) continue;
// dep[v]=dep[u]+1;
// fa[0][v]=u;
// dfs(v, u);
// }
// }
// int lca(int a, int b) {
// if (dep[a]<dep[b]) swap(a, b);
// while (dep[a]>dep[b]) a=fa[lg[dep[a]-dep[b]]-1][a];
// if (a==b) return a;
// for (int i=lg[dep[a]]-1; ~i; --i)
// if (fa[i][a]!=fa[i][b])
// a=fa[i][a], b=fa[i][b];
// return fa[0][a];
// }
// int dis(int a, int b) {return dep[a]+dep[b]-2*dep[lca(a, b)];}
// // void isok(int a, int da, int b, int db, int x, int i) {
// // assert(x>=1&&x<=n);
// // // cout<<dis(a, x)<<' '<<da<<endl;
// // if (dis(a, x)!=da || dis(b, x)!=db) cerr<<"line: "<<i<<endl;
// // assert(dis(a, x)==da && dis(b, x)==db);
// // }
// // void isnone(int a, int da, int b, int db, int i) {
// // for (int x=1; x<=n; ++x) {
// // if (dis(a, x)==da && dis(b, x)==db) cerr<<"line: "<<i<<endl;
// // assert(dis(a, x)!=da || dis(b, x)!=db);
// // }
// // }
// void solve() {
// dep[1]=1; dfs(1, 0);
// for (int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
// for (int i=1,a,b,da,db; i<=q; ++i) {
// // cout<<"i: "<<i<<endl;
// a=read(); da=read(); b=read(); db=read();
// for (int j=1; j<=n; ++j) if (dis(a, j)==da&&dis(b, j)==db) {
// printf("%d\n", j);
// goto jump;
// }
// puts("-1");
// jump: ;
// }
// }
// }
namespace task1{
int _a[N], _b[N], _da[N], _db[N];
int dep[N], mdep[N], back[N], mlen[N], fa[21][N], lg[N], ans[N];
void dfs1(int u, int pa) {
mdep[u]=dep[u];
for (int i=1; i<21; ++i)
if (dep[u]>=1<<i) fa[i][u]=fa[i-1][fa[i-1][u]];
else break;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==pa) continue;
dep[v]=dep[u]+1;
fa[0][v]=u;
back[v]=u;
dfs1(v, u);
mdep[u]=max(mdep[u], mdep[v]);
}
mlen[u]=mdep[u]-dep[u];
}
int lca(int a, int b) {
if (dep[a]<dep[b]) swap(a, b);
while (dep[a]>dep[b]) a=fa[lg[dep[a]-dep[b]]-1][a];
if (a==b) return a;
for (int i=lg[dep[a]]-1; ~i; --i)
if (fa[i][a]!=fa[i][b])
a=fa[i][a], b=fa[i][b];
return fa[0][a];
}
int anc(int a, int k) {
for (int i=lg[dep[a]]-1; ~i; --i)
if (k>=1<<i) a=fa[i][a], k-=1<<i;
return a;
}
int dis(int a, int b) {return dep[a]+dep[b]-2*dep[lca(a, b)];}
namespace sub1{
set<int> que[N];
vector<pair<int, int>> buc[N], del[N], rec[N];
void dfs2(int u, int fa) {
for (auto it:del[u]) if (que[it.fir].find(it.sec)!=que[it.fir].end()) {
que[it.fir].erase(it.sec);
rec[u].pb(it);
}
for (auto it:buc[u]) que[it.fir].insert(it.sec);
for (auto it:que[dep[u]]) ans[it]=u;
que[dep[u]].clear();
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dfs2(v, u);
}
for (auto it:buc[u]) que[it.fir].erase(it.sec);
for (auto it:rec[u]) que[it.fir].insert(it.sec);
}
}
// namespace sub2{
// set<int> que[N];
// vector<pair<int, int>> buc[N], del[N], rec[N];
// void dfs2(int u, int fa) {
// for (auto it:del[u]) if (que[it.fir].find(it.sec)!=que[it.fir].end()) {
// que[it.fir].erase(it.sec);
// rec[u].pb(it);
// }
// for (auto it:buc[u]) que[it.fir].insert(it.sec);
// for (auto it:que[dep[u]]) ans[it]=u;
// que[dep[u]].clear();
// for (int i=head[u],v; ~i; i=e[i].next) {
// v = e[i].to;
// if (v==fa) continue;
// dfs2(v, u);
// }
// for (auto it:buc[u]) que[it.fir].erase(it.sec);
// for (auto it:rec[u]) que[it.fir].insert(it.sec);
// }
// }
// namespace sub3{
// set<int> que[N];
// vector<pair<int, int>> buc[N], del[N], rec[N];
// void dfs2(int u, int fa) {
// for (auto it:del[u]) if (que[it.fir].find(it.sec)!=que[it.fir].end()) {
// que[it.fir].erase(it.sec);
// rec[u].pb(it);
// }
// for (auto it:buc[u]) que[it.fir].insert(it.sec);
// for (auto it:que[dep[u]]) ans[it]=u;
// que[dep[u]].clear();
// for (int i=head[u],v; ~i; i=e[i].next) {
// v = e[i].to;
// if (v==fa) continue;
// dfs2(v, u);
// }
// for (auto it:buc[u]) que[it.fir].erase(it.sec);
// for (auto it:rec[u]) que[it.fir].insert(it.sec);
// }
// }
namespace sub4{
set<int> que[N];
vector<pair<int, int>> buc[N], del[N], rec[N];
vector<pair<int, int>> tem[N];
void dfs2(int u, int fa) {
for (auto it:del[u]) if (que[it.fir].find(it.sec)!=que[it.fir].end()) {
que[it.fir].erase(it.sec);
rec[u].pb(it);
}
for (auto it:buc[u]) que[it.fir].insert(it.sec);
for (auto it:que[dep[u]]) ans[it]=u;
que[dep[u]].clear();
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
dfs2(v, u);
}
for (auto it:buc[u]) que[it.fir].erase(it.sec);
for (auto it:rec[u]) que[it.fir].insert(it.sec);
}
void dfs3(int u, int fa, int maxn, int pos, int dis) {
for (auto it:tem[u]) {
if (maxn>=it.fir) {
buc[pos].pb({dep[pos]+it.fir-dis, it.sec});
del[anc(u, dis-1)].pb({dep[pos]+it.fir-dis, it.sec});
}
}
pair<int, int> fir, sec;
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
if (mlen[v]+1>=fir.fir) sec=fir, fir={mlen[v]+1, v};
else if (mlen[v]+1>sec.fir) sec={mlen[v]+1, v};
}
if (maxn>=fir.fir) sec=fir, fir={maxn, pos};
else if (maxn>sec.fir) sec={maxn, pos};
for (int i=head[u],v; ~i; i=e[i].next) {
v = e[i].to;
if (v==fa) continue;
if (v==fir.sec) dfs3(v, u, sec.fir+1, sec.sec==pos?pos:u, sec.sec==pos?dis+1:1);
else dfs3(v, u, fir.fir+1, fir.sec==pos?pos:u, fir.sec==pos?dis+1:1);
}
}
void query(int t, int len, int id) {
tem[t].pb({len, id});
}
void solve() {
dfs3(1, 0, -INF, 0, 0);
dfs2(1, 0);
}
}
void solve() {
// cout<<double(sizeof(sub4::buc)*16)/1000/1000<<endl; exit(0);
// cout<<double(sizeof(lg)*31+sizeof(sub4::que)*4+sizeof(sub4::buc)*16)/1000/1000<<endl; exit(0);
dep[1]=1; dfs1(1, 0);
memset(ans, -1, sizeof(ans));
for (int i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for (int i=1,a,b,da,db; i<=q; ++i) {
// cout<<"i: "<<i<<endl;
_a[i]=a=read(); _da[i]=da=read(); _b[i]=b=read(); _db[i]=db=read();
if (!da||!db) {
// cout<<"case1"<<endl;
if (!da) ans[i]=a;
else ans[i]=b;
continue;
}
if (a==b) {
if (da!=db) continue;
if (da<dep[a]) ans[i]=anc(a, da);
else sub1::buc[a].pb({dep[a]+da, i});
}
int t=lca(a, b), dis=dep[a]+dep[b]-2*dep[t], lena=dep[a]-dep[t], lenb=dep[b]-dep[t];
// cout<<"t: "<<t<<endl;
// cout<<"dis: "<<dis<<endl;
if (da+db==dis) {
// cout<<"case4"<<endl;
if (da<=lena) ans[i]=anc(a, da);
else assert(db<=lenb), ans[i]=anc(b, db);
}
else if (da+db>dis) {
if (db-dis==da) {
// cout<<"case2"<<endl;
sub1::buc[a].pb({dep[a]+da, i});
if (a==t) sub1::del[anc(b, lenb-1)].pb({dep[a]+da, i});
}
if (da-dis==db) {
// cout<<"case3"<<endl;
sub1::buc[b].pb({dep[b]+db, i});
if (b==t) sub1::del[anc(a, lena-1)].pb({dep[b]+db, i});
}
if ((da+db-dis)&1) continue;
int len=(da+db-dis)/2;
// cout<<"dis: "<<dis<<endl;
// cout<<"len: "<<len<<endl;
if (lena+len==da && lenb+len==db) {
if (len<dep[t]) ans[i]=anc(t, len);
else {
// --len;
// for (int u=back[t],lst=t; u; lst=u,u=back[u],--len)
// sub4::buc[u].pb({dep[u]+len, i}), sub4::del[lst].pb({dep[u]+len, i});
// len=(da+db-dis)/2;
sub4::query(t, len, i);
}
}
// if (a!=t&&b!=t) { // in lca's subtree
// sub2::buc[t].pb({dep[t]+len, i});
// sub2::del[anc(a, lena-1)].pb({dep[t]+len, i});
// sub2::del[anc(b, lenb-1)].pb({dep[t]+len, i});
// }
// if (lena>=2) sub3::query(a, t, len, i);
// if (lenb>=2) sub3::query(b, t, len, i);
if (a!=t && b!=t) { // in lca's subtree
if (lena+len==da && lenb+len==db) {
sub1::buc[t].pb({dep[t]+len, i});
sub1::del[anc(a, lena-1)].pb({dep[t]+len, i});
sub1::del[anc(b, lenb-1)].pb({dep[t]+len, i});
}
}
if (lena>=2 && len<da && da-len<lena) {
int u=anc(a, da-len), v=anc(a, da-len-1);
sub1::buc[u].pb({dep[u]+len, i});
sub1::del[v].pb({dep[u]+len, i});
}
if (lenb>=2 && len<db && db-len<lenb) {
int u=anc(b, db-len), v=anc(b, db-len-1);
sub1::buc[u].pb({dep[u]+len, i});
sub1::del[v].pb({dep[u]+len, i});
}
}
}
sub1::dfs2(1, 0);
// sub2::dfs2(1, 0);
// sub3::dfs2(1, 0);
sub4::solve();
for (int i=1; i<=q; ++i) printf("%d\n", ans[i]);
}
}
signed main()
{
freopen("hunting.in", "r", stdin);
freopen("hunting.out", "w", stdout);
n=read(); q=read();
memset(head, -1, sizeof(head));
for (int i=1,u,v; i<n; ++i) {
u=read(); v=read();
add(u, v); add(v, u);
}
// if (n<=3000 && q<=3000) force::solve();
// else task1::solve();
task1::solve();
return 0;
}