题解 挖宝

传送门

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;
}
posted @ 2022-04-13 18:50  Administrator-09  阅读(3)  评论(0编辑  收藏  举报