• 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
    ",ansed);
            }
             inti(0,N1);
             inti(1,N2);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    C++11模板类使用心得
    Linux下MakeFile初探
    Leetcode 35 Search Insert Position 二分查找(二分下标)
    Leetcode 4 Median of Two Sorted Arrays 二分查找(二分答案+二分下标)
    数据库分库分表的应用场景及方法分析
    DB主从一致性的几种解决方法
    Redis主从复制和集群配置
    RPC vs RESTful
    Mysql锁详解
    BIO与NIO、AIO的区别
  • 原文地址:https://www.cnblogs.com/Opaser/p/4132202.html
Copyright © 2020-2023  润新知