又是一道简单题
给出一棵有根树,每次查询给出两个节点 u 和 v,假设节点 f 是u,v的最近公共祖先,请查询以 f 为根的子树中,不在 u 到 v 这条链上且标号最小的节点。
输入格式
第一行输入正整数 T(T <= 30),表示共有T组输入数据。
对于每组数据,第一行输入两个正整数 n,m(n <= 50000,m <= 50000),表示节点数和询问数,节点编号 1 到 n,其中 1 是根节点。
接下来 n - 1 行,每行输入两个正整数u,v,表示标号为u和v的节点间有一条边。
接下来 m 行,每行输入两个正整数u,v,表示一次询问。
保证所有输入数据均合法。
输出格式
对于每次询问,输出答案。如不存在输出-1。
样例输入
1 3 3 1 2 1 3 1 2 1 3 2 3
样例输出
3 2 -1
分析:考虑树链剖分;
把子树按dfs序可以展开到一维,然后对于链,可以将这个区间分成logn的部分,对于每个部分求最小值即可;
复杂度nlognlogn;
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <climits> #include <cstring> #include <string> #include <set> #include <bitset> #include <map> #include <queue> #include <stack> #include <vector> #include <cassert> #include <ctime> #define rep(i,m,n) for(i=m;i<=n;i++) #define mod 1000000007 #define inf 0x3f3f3f3f #define vi vector<int> #define pb push_back #define mp make_pair #define fi first #define se second #define ll long long #define pi acos(-1.0) #define pii pair<int,int> #define ls rt<<1 #define rs rt<<1|1 #define sys system("pause") const int maxn=1e5+10; const int N=1e5+10; using namespace std; ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);} ll qpow(ll p,ll q){ll f=1;while(q){if(q&1)f=f*p%mod;p=p*p%mod;q>>=1;}return f;} int n,m,k,t,st[maxn],ed[maxn],dep[maxn],fa[20][maxn],bel[maxn],son[maxn],pos[maxn],a[maxn],dfs_cl,mi[maxn<<2]; vi e[maxn]; void dfs1(int x,int y) { dep[x]=dep[y]+1; fa[0][x]=y; son[x]=1; for(int i=1;fa[i-1][fa[i-1][x]];i++) { fa[i][x]=fa[i-1][fa[i-1][x]]; } for(int i=0;i<e[x].size();i++) { int z=e[x][i]; if(z==y)continue; dfs1(z,x); son[x]+=son[z]; } } void dfs2(int x,int y,int ch) { int ma=0; pos[x]=++dfs_cl; st[x]=dfs_cl; a[dfs_cl]=x; bel[x]=ch; for(int i=0;i<e[x].size();i++) { int z=e[x][i]; if(z==y)continue; if(son[z]>son[ma])ma=z; } if(ma!=0)dfs2(ma,x,ch); for(int i=0;i<e[x].size();i++) { int z=e[x][i]; if(z==y||z==ma)continue; dfs2(z,x,z); } ed[x]=dfs_cl; } int lca(int x,int y) { if(dep[x]<dep[y])swap(x,y); for(int i=19;i>=0;i--)if(dep[fa[i][x]]>=dep[y])x=fa[i][x]; if(x==y)return x; for(int i=19;i>=0;i--) { if(fa[i][x]!=fa[i][y])x=fa[i][x],y=fa[i][y]; } return fa[0][x]; } void pup(int l,int r,int rt) { mi[rt]=min(mi[ls],mi[rs]); } void build(int l,int r,int rt) { if(l==r) { mi[rt]=a[l]; return; } int mid=l+r>>1; build(l,mid,ls); build(mid+1,r,rs); pup(l,r,rt); } int gao(int L,int R,int l,int r,int rt) { if(L==l&&R==r)return mi[rt]; int mid=l+r>>1; if(R<=mid)return gao(L,R,l,mid,ls); else if(L>mid)return gao(L,R,mid+1,r,rs); else return min(gao(L,mid,l,mid,ls),gao(mid+1,R,mid+1,r,rs)); } void upd(vector<int>&a,int x,int y) { while(bel[x]!=bel[y]) { if(dep[bel[x]]<dep[bel[y]])swap(x,y); a.pb(pos[x]); a.pb(pos[bel[x]]); x=fa[0][bel[x]]; } if(pos[x]>pos[y])swap(x,y); a.pb(pos[y]); a.pb(pos[x]); } int main() { int i,j; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); rep(i,1,n)e[i].clear(); rep(i,1,n)rep(j,0,19)fa[j][i]=0; rep(i,1,n-1)scanf("%d%d",&j,&k),e[j].pb(k),e[k].pb(j); dfs1(1,0); dfs_cl=0; dfs2(1,0,1); build(1,n,1); while(m--) { int x,y; scanf("%d%d",&x,&y); vector<int>tmp; int lc=lca(x,y); upd(tmp,x,y); int s=st[lc],t=ed[lc]; if(lc<1||lc>n)return 0; sort(tmp.begin(),tmp.end()); int mi=1e9; for(i=0;i<tmp.size();i+=2) { if(s<=tmp[i]-1)mi=min(mi,gao(s,tmp[i]-1,1,n,1)); s=tmp[i+1]+1; } if(s<=t)mi=min(mi,gao(s,t,1,n,1)); printf("%d ",mi==1e9?-1:mi); } } return 0; }