hdu 5111 树链剖分加函数式线段树

这题说的是给了两棵树,各有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\n",ansed);
        }
         inti(0,N1);
         inti(1,N2);
    }
    return 0;
}
View Code

 

posted @ 2014-11-29 23:15  来自大山深处的菜鸟  阅读(219)  评论(0编辑  收藏  举报