这题说的是给了两棵树,各有100000 个节点,然后Q个操作Q<=50000; 每个操作L1 R1 L2 R2。因为对于每棵树都有一个与本棵树其他点与众不同的值, 最后问 在树上从L1到R1这条路径上与第二棵树L2 到 R2 这条路上的点 的权值相等的有多少个
这题挺麻烦的 写的想吐了
首先将第一棵树进行树剖,然后通过树剖可以离散出这颗树的每个点的编号从1,2,3,4...N1,然后将第二棵树进行树剖,按照树剖的值依次插入,以第一棵树离散出的值为叶节点的函数式线段树,
如果第二棵树的值在第一棵树种中不到,那么就直接将他插在值为0的叶节点上。我们可以知道在书剖中他们在同一条链上是相等的,所以他们在函数式线段树中也是连续的。通过这样我们可以使用类似区间第K大的解法解决这个问题
#include <iostream> #include <cstdio> #include <algorithm> #include <string.h> #include <vector> #pragma comment(linker,"/STACk:10240000,10240000") using namespace std; const int maxn =100005; vector<int> F[2][maxn],rea[2],fro[2]; int p[2][maxn],fp[2][maxn],XX[2],top[2][maxn]; int depth[2][maxn],num[2][maxn],son[2][maxn],fa[2][maxn]; int L1[maxn],V[maxn],data[2][maxn],T[maxn]; int Ls[maxn*18],Rs[maxn*18],Ve[maxn*18],len; struct point{ int x,loc; bool operator<(const point &A)const{ return x<A.x||(x==A.x&&loc<A.loc); } }PP[maxn]; void inti(int loc, int n){ for(int i=0; i<=n; ++i) F[loc][i].clear(); } void dfs(int loc, int now, int per,int dep){ fa[loc][now]=per; son[loc][now]=-1; depth[loc][now]=dep; num[loc][now]=1; int ge=F[loc][now].size(); for(int i=0; i<ge; ++i){ int to = F[loc][now][i]; if(to==per||to==now)continue; dfs(loc,to,now,dep+1); num[loc][now]+=num[loc][to]; if(son[loc][now]==-1||num[loc][ son[loc][now] ]<num[loc][to]) son[loc][now]=to; } } void fine(int loc, int now , int X,int per){ top[loc][now]=X; XX[loc]++; p[ loc ][ now ]=XX[ loc ]; fp[ loc ][ XX[loc] ]=now; if( son[ loc ][ now ] != -1 ) fine( loc , son[loc][now] , X ,now); int ge=F[loc][now].size(); for(int i=0; i<ge; ++i){ int to=F[loc][now][i]; if( to==son[loc][now]||to==now||to==per ) continue; fine(loc,to,to,now); } } void inser(int L, int R, int K, int per, int &x){ x = ++len; Ls[x]=Ls[per]; Rs[x]=Rs[per]; Ve[x]=Ve[per]+1; if(L==R)return ; int mid=(L+R)>>1; if(K<=mid) inser( L, mid , K, Ls[per] , Ls[x] ); else inser( mid+1 , R , K , Rs[per] , Rs[x] ); } int ansed,Lc,Rc; void query(int L, int R, int per, int cur){ if(Lc<=L&&R<=Rc){ ansed += Ve[cur]-Ve[per];return; } if(L>=R)return ; int mid = (L+R)>>1; if(Lc<=mid) query(L, mid , Ls[per],Ls[cur]); if(Rc>mid) query(mid+1, R, Rs[per],Rs[cur]); } void solve(int loc, int p1, int p2){ int f1=top[loc][p1],f2=top[loc][p2]; int num=0; while(f1!=f2){ num++; if(num>20) break; if(depth[loc][f1]<depth[loc][f2]){ int t=p1; p1=p2; p2=t; t=f1; f1=f2; f2=t; } fro[loc].push_back( p[loc][f1] ); rea[loc].push_back( p[loc][p1] ); p1=fa[loc][f1]; f1=top[loc][p1]; } if(depth[loc][p1]<depth[loc][p2]){ int t=p1; p1=p2; p2=t; } fro[loc].push_back(p[loc][p2]); rea[loc].push_back(p[loc][p1]); } int main() { int N1, N2; while(scanf("%d",&N1)==1){ for(int i=1; i<N1; ++i){ int f; scanf("%d",&f); F[0][f].push_back(i+1); } XX[0]=0; dfs(0,1,0,1); fine(0,1,1,0); for(int i=0; i<N1; ++i){ scanf("%d",&data[0][i]); PP[i].x = data[0][i]; PP[i].loc = i+1; } sort(PP,PP+N1); for(int i=0; i<N1; ++i) { V[i]=PP[i].x; L1[i]=p[ 0 ][ PP[i].loc ]; } scanf("%d",&N2); for(int i=1; i<N2; ++i){ int fa; scanf("%d",&fa); F[1][fa].push_back(i+1); } XX[1]=0; dfs(1,1,0,1); fine(1,1,1,0); for(int i=1; i<=N2; ++i){ scanf("%d",&data[1][i]); int loc = lower_bound(V,V+N1,data[1][i])-V; if(V[loc]==data[1][i]){ data[1][i]=L1[loc]; }else data[1][i]=0; } Ls[0]=Rs[0]=Ve[0]=len=0; for(int i=1; i <= N2; ++ i ){ int loc=fp[ 1 ][ i ]; inser(0,N1,data[ 1 ][ loc ],T[ i-1 ],T[ i ]); } int Q; scanf("%d",&Q); for(int i=0; i<Q; ++i){ int L1,R1,L2,R2; scanf("%d%d%d%d",&L1,&R1,&L2,&R2); rea[0].clear(); fro[0].clear(); rea[1].clear(); fro[1].clear(); solve(0,L1,R1); solve(1,L2,R2); ansed=0; for(int j=0; j<(int)rea[0].size(); ++j){ Lc=fro[0][j]; Rc=rea[0][j]; if(Lc>Rc){ int t=Lc; Lc=Rc; Rc=t; } for(int k=0; k<(int)rea[1].size(); ++k){ int L=fro[1][k],R=rea[1][k]; if(L>R){ int t=L; L=R; R=t; } query( 0,N1,T[L-1],T[R] ); } } printf("%d ",ansed); } inti(0,N1); inti(1,N2); } return 0; }