#4509. Three points 2
题目描述
有一棵大树.
已知 $a,b,c$,你需要找出 $X,Y,Z$,满足 $dis(X,Y)=a,\ dis(X,Z)=b,\ dis(Y,Z)=c$.
数据范围
$3\le n,Q\le 2\times 10^5$,$1\le a,b,c<n$
题解
考虑一下到这三条路径会交于一个点 $A$ ,而 $A$ 到 $X,Y,Z$的路径长度可以先算出来,设为 $x,y,z$ 且 $x \ge y \ge z$
我们发现如果一个点能够成为这个点 $A$,则需要满足它的三长链分别不小于 $x,y,z$ ,即如果三长链长度为 $x' \ge y' \ge z'$ ,则 $x \le x',y \le y',z \le z'$
所以我们可以利用 $dp$ 换根把每个点的三长链及其对应的叶子结点求出来,然后就是个经典的三维偏序问题啦,可以直接用树状数组解决
效率: $O(nlogn)$
代码
#include <bits/stdc++.h> #define P pair<int,int> #define _(d) while(d(isdigit(c=getchar()))) using namespace std;const int N=2e5+5,Z=N<<1; int R(){char c;_(!);int x=c^48;_()x=(x<<3)+(x<<1)+(c^48);return x;} int a[N],b[N],c[N],s[N],Q,n,hd[N],V[Z],nx[Z],t,fa[N][20],dp[N],f[N][3],g[N][3],d[N][3],w[4],k[4],e[N],F[Z][22],Lg[Z],in[N],C; P ax[N];struct O{int a,b,c,x,g;}p[Z],h[N]; bool cmp(O A,O B){ if (A.a==B.a){ if (A.b==B.b){ if (A.c==B.c) return A.g>B.g; return A.c>B.c; } return A.b>B.b; } return A.a>B.a; } void add(int u,int v){ nx[++t]=hd[u];V[hd[u]=t]=v;in[v]++; } void dfs(int x,int fr){ fa[x][0]=fr;dp[x]=dp[fr]+1; F[++C][0]=x;e[x]=C; for (int i=1;fa[fa[x][i-1]][i-1];i++) fa[x][i]=fa[fa[x][i-1]][i-1]; for (int i=hd[x];i;i=nx[i]) if (V[i]!=fr) dfs(V[i],x),F[++C][0]=x; } void work(int x,int j,int v){ for (int i=0;i<3;i++) if (f[x][j]+1>f[v][i]){ for (int s=2;s>i;s--) f[v][s]=f[v][s-1],d[v][s]=d[v][s-1],g[v][s]=g[v][s-1]; f[v][i]=f[x][j]+1;d[v][i]=d[x][j];g[v][i]=x;break; } } void dp1(int x,int fr){ f[x][0]=0;f[x][1]=f[x][2]=-1;d[x][0]=x; for (int v,i=hd[x];i;i=nx[i]) if ((v=V[i])!=fr) dp1(v,x),work(v,0,x); } void dp2(int x,int fr){ if (in[x]>1) p[++t]=(O){f[x][0],f[x][1],f[x][2],x,1}; for (int v,i=hd[x];i;i=nx[i]) if ((v=V[i])!=fr) work(x,g[x][0]==v,v),dp2(v,x); } void update(int x,P v){ for (;x;x-=x&-x) ax[x]=max(ax[x],v); } P query(int x){ P A=ax[x]; for (;x<=n;x+=x&-x) A=max(A,ax[x]); return A; } int Min(int x,int y){return dp[x]<dp[y]?x:y;} int lca(int l,int r){ if (l>r) swap(l,r);int i=Lg[r-l+1]; return Min(F[l][i],F[r-(1<<i)+1][i]); } int dis(int u,int v){ int l=lca(e[u],e[v]); return dp[u]+dp[v]-(dp[l]<<1); } int find(int u,int y,int ds){ int v=d[u][y],l=lca(e[u],e[v]); if (dp[u]-dp[l]<ds){ ds-=dp[u]-dp[l]; ds=dp[v]-dp[l]-ds;u=v; } for (int i=0;ds;ds>>=1,i++) if (ds&1) u=fa[u][i]; return u; } int main(){ n=R();for (int u,v,i=1;i<n;i++) u=R()+1,v=R()+1,add(u,v),add(v,u); dfs(1,0);t=0;dp1(1,0);dp2(1,0);Q=R(); for (int i=2;i<=C;i++) Lg[i]=Lg[i>>1]+1; for (int i=C;i;i--) for (int j=1;i+(1<<j)<=C+1;j++) F[i][j]=Min(F[i][j-1],F[i+(1<<(j-1))][j-1]); for (int x,y,z,i=1;i<=Q;i++){ a[i]=R();b[i]=R();c[i]=R();x=a[i]+b[i]-c[i]; y=a[i]+c[i]-b[i];z=b[i]+c[i]-a[i]; if (x>=0 && y>=0 && z>=0 && !((x&1)&(y&1)&(z&1))){ x>>=1;y>>=1;z>>=1;if (x<y) swap(x,y); if (x<z) swap(x,z);if (y<z) swap(y,z); h[i]=p[++t]=(O){x,y,z,i,0}; } } sort(p+1,p+t+1,cmp); for (int i=1;i<=t;i++) if (p[i].g) update(p[i].b,make_pair(p[i].c,p[i].x)); else{ P A=query(p[i].b); if (A.second && A.first>=p[i].c) s[p[i].x]=A.second; } for (int i=1;i<=Q;i++) if (s[i]){ w[k[1]=1]=find(s[i],0,h[i].a); w[k[2]=2]=find(s[i],1,h[i].b); w[k[3]=3]=find(s[i],2,h[i].c); do{ if (dis(w[k[1]],w[k[2]])==a[i] && dis(w[k[1]],w[k[3]])==b[i] && dis(w[k[2]],w[k[3]])==c[i]){ printf("%d %d %d\n",w[k[1]]-1,w[k[2]]-1,w[k[3]]-1);break; } }while(next_permutation(k+1,k+4)); } else puts("-1"); return 0; }