zoukankan      html  css  js  c++  java
  • 【xsy1156】 树套树(tree) 倍增

    题目大意:给你$m$棵由$n$个点构成的全等的树$A$。这$m$棵树之间有$m-1$条边相连,组成了一棵大树。

    有$q$组询问,每次询问这棵大树上两点之间的距离。

    $n,m,q≤10^5$

    这是一道小视野双倍经验题

    这一题有一种显然的虚树做法,这种做法我之前打过了,这次换一种做法。

    如果询问所在两点在同一棵小树内,那么显然直接倍增就可以了。

    我们将连接$m$棵树的边抽出来,构成另外一棵树(暂且称作树$B$),节点$p$表示第$p$棵树,我们钦定这棵树的$1$号点为根。

    我们令$up1[i]$表示树$B$中,连接$i$号点$father$所在的边,它在第$i$棵小树中所连接的节点。

    令$up2[i]$表示树$B$中,连接$i$号点$father$所在的边,它在第$fa[i]$棵小树中所连接的点。

    令$dis[i]$表示从树$B$的第$1$号树的$1$号节点开始,到达小树$i$第$up1[i]$号节点的距离。

     

    对于一组询问$(w,x,y,z)$,我们求出$w,y$的$lca$,令$w'$表示在$w$到$lca$的路径上,离$lca$最近的点(不包括$lca$本身),同理求出$y'$。

    设最终答案为$ans$

    若存在$w'$,则$ans+=A.dis(x,up1[x])+dis[w]-dis[w']$,并令$x=up2[w']$。

    若存在$y'$,则$ans+=A.dis(z,up1[z])+dis[y]-dis[y']$,并令$z=up2[y']$。

    最后$ans+=A.dis(x,z)$即可。

    注意细节

     1 #include<bits/stdc++.h>
     2 #define M 100005
     3 #define L long long
     4 using namespace std;
     5 int n,m,q;
     6 struct tree1{
     7     struct edge{int u,next;}e[M*2]; int head[M],use=0;
     8     void add(int x,int y){use++;e[use].u=y;e[use].next=head[x];head[x]=use;}
     9     int f[M][20],dep[M];
    10     void dfs(int x,int fa){
    11         f[x][0]=fa; dep[x]=dep[fa]+1;
    12         for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1];
    13         for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa) dfs(e[i].u,x);
    14     }
    15     int getlca(int x,int y){
    16         if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y];
    17         for(int i=19;~i;i--) if((1<<i)&cha) x=f[x][i];
    18         for(int i=19;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    19         if(x==y) return x; return f[x][0];
    20     }
    21     int getdis(int x,int y){
    22         int lca=getlca(x,y);
    23         return dep[x]+dep[y]-2*dep[lca];
    24     }
    25     void init(){
    26         for(int i=1;i<n;i++){
    27             int x,y; scanf("%d%d",&x,&y);
    28             add(x,y); add(y,x);
    29         }
    30         dfs(1,0);
    31     }
    32 }a;
    33 struct tree2{
    34     struct edge{int u,us,ut,next;}e[M*2]; int head[M],use=0;
    35     void add(int x,int y,int us,int ut){use++;e[use].u=y;e[use].us=us;e[use].ut=ut;e[use].next=head[x];head[x]=use;}
    36     int f[M][20],dep[M],up1[M],up2[M]; L dis[M];
    37     void dfs(int x,int fa){
    38         f[x][0]=fa; dep[x]=dep[fa]+1;
    39         for(int i=1;i<20;i++) f[x][i]=f[f[x][i-1]][i-1];
    40         for(int i=head[x];i;i=e[i].next) if(e[i].u!=fa){
    41             up1[e[i].u]=e[i].ut; up2[e[i].u]=e[i].us;
    42             dis[e[i].u]=dis[x]+a.getdis(up1[x],e[i].us)+1;
    43             dfs(e[i].u,x);
    44         }
    45     }
    46     int getlca(int x,int y){
    47         if(dep[x]<dep[y]) swap(x,y); int cha=dep[x]-dep[y];
    48         for(int i=19;~i;i--) if((1<<i)&cha) x=f[x][i];
    49         for(int i=19;~i;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    50         if(x==y) return x; return f[x][0];
    51     }
    52     int jump(int x,int k){
    53         for(int i=19;~i;i--) if((1<<i)&k) x=f[x][i];
    54         return x;
    55     }
    56     void init(){
    57         for(int i=1;i<m;i++){
    58             int x,X,y,Y; scanf("%d%d%d%d",&x,&X,&y,&Y);
    59             add(x,y,X,Y); add(y,x,Y,X);
    60         }
    61         dfs(1,0);
    62     }
    63 }b;
    64 int main(){
    65     scanf("%d%d%d",&n,&m,&q);
    66     a.init();
    67     b.init();
    68     while(q--){
    69         int x,X,y,Y; scanf("%d%d%d%d",&x,&X,&y,&Y);
    70         int lca=b.getlca(x,y); 
    71         L ans=0;
    72         if(x!=lca){
    73             ans+=a.getdis(X,b.up1[x]);
    74             int xx=b.jump(x,b.dep[x]-b.dep[lca]-1);
    75             ans+=b.dis[x]-b.dis[xx]+1;
    76             X=b.up2[xx];
    77         }
    78         if(y!=lca){
    79             ans+=a.getdis(Y,b.up1[y]);
    80             int yy=b.jump(y,b.dep[y]-b.dep[lca]-1);
    81             ans+=b.dis[y]-b.dis[yy]+1;
    82             Y=b.up2[yy];
    83         }
    84         ans+=a.getdis(X,Y);
    85         printf("%lld
    ",ans);
    86     }
    87 }
  • 相关阅读:
    数值项目的格式化
    ORACLE ERROR CODE代表的意思
    深入了解 Microsoft AJAX Library
    调用MSScriptContro来运算字符串表达式
    C# 调用带参数EXE文件及带启动参数EXE制作
    将DataTable或Ilist<>转换成JSON格式
    客户端控件调用服务器的参数
    调用ICodeCompiler来计算字符串表达式
    录像工具
    今天是开博客园的第一天
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/9811817.html
Copyright © 2011-2022 走看看