• 【Foreign】旅行路线 [倍增]


    旅行路线

    Time Limit: 20 Sec  Memory Limit: 256 MB

    Description

      

    Input

      

    Output

      仅一行一个整数表示答案。

    Sample Input

      3
      2 1
      3 1

    Sample Output

      3

    HINT

      

    Main idea

      将每个点的入度作为标识,问从叶节点到根有几个本质不同的串。

    Solution

      我们先考虑暴力的写法,显然无重复的话是答案是ΣDep[i],那么我们构建出一棵树,然后从任意两个点暴力往上判断找到最长相同的长度,然后减去这个长度即可。

      我们发现这个算法慢在哪里?就是一步步判断太慢了!对于这种问题,我们显然可以使用倍增

      我们用字符串的哈希值来判断字符串是否相同,那么就记录一个hash[u][i]表示从u到往上跳(2^i)-1的哈希值,然后我们按照每个点到根的哈希值排序,显然得到的序列会满足:哈希值有相同的必然会在一起,若相同的长则会更接近。

      然后我们O(n)比较相邻两个的哈希值,用倍增来跳,找到最长长度减去即可。

    Code

      1 #include<iostream>  
      2 #include<algorithm>  
      3 #include<cstdio>  
      4 #include<cstring>  
      5 #include<cstdlib>  
      6 #include<cmath>  
      7 using namespace std;
      8 typedef long long s64;
      9 const int ONE = 100005;
     10 const int INF = 214783640;
     11 const int P = 21;
     12 
     13 int n;
     14 int x,y; 
     15 int Input[ONE];
     16 int Dep[ONE],id[ONE];
     17 int f[ONE][22];
     18 s64 Q[ONE],hash[ONE][22];
     19 int next[ONE],first[ONE],go[ONE],tot;
     20 s64 Ans;
     21 
     22 int get()
     23 { 
     24         int res=1,Q=1;    char c;
     25         while( (c=getchar())<48 || c>57)
     26         if(c=='-')Q=-1;
     27         if(Q) res=c-48; 
     28         while((c=getchar())>=48 && c<=57) 
     29         res=res*10+c-48; 
     30         return res*Q; 
     31 }
     32 
     33 int Add(int u,int v)
     34 {
     35         next[++tot]=first[u];    first[u]=tot;    go[tot]=v;
     36 }
     37 
     38 void Dfs(int u)
     39 {
     40         hash[u][0] = Input[u];
     41         
     42         for(int i=0;i<=P-1;i++)
     43         {
     44             f[u][i+1] = f[f[u][i]][i];
     45             hash[u][i+1] = hash[u][i] + hash[f[u][i]][i] * Q[i];
     46         }
     47         
     48         for(int e=first[u];e;e=next[e])
     49         {
     50             int v=go[e];
     51             f[v][0] = u;
     52             Dep[v] = Dep[u] + 1;
     53             Dfs(v);
     54         }
     55 }
     56 
     57 bool cmp(int x,int y)
     58 {
     59         for(int i=P-1;i>=0;i--)
     60         if(Dep[x]>=(1<<i) && hash[x][i] == hash[y][i])
     61         {
     62             x = f[x][i];
     63             y = f[y][i];
     64         }
     65         return hash[x][0] < hash[y][0];
     66 }
     67 
     68 int Same(int x,int y)
     69 {
     70         int res=0;
     71         for(int i=P-1;i>=0;i--)
     72         if(Dep[x]>=(1<<i) && hash[x][i] == hash[y][i])
     73         {
     74             x = f[x][i];
     75             y = f[y][i];
     76             res += (1<<i);
     77         }
     78         return res;
     79 }
     80 
     81 int main()
     82 {
     83         n=get();
     84         for(int i=1;i<=n;i++) id[i]=i;
     85         for(int i=1;i<n;i++)
     86         {
     87             x=get();    y=get();
     88             Add(y,x);
     89             Input[x]++;    Input[y]++;
     90         }
     91         
     92         Q[0] = 1e9+7;
     93         for(int i=1;i<=P;i++) Q[i] = Q[i-1] * Q[i-1];
     94         
     95         Dep[1]=1;    Dfs(1);
     96         sort(id+1,id+n+1,cmp);
     97         
     98         Ans = Dep[id[1]];
     99         for(int i=2;i<=n;i++)
    100         {
    101             Ans += Dep[id[i]] - Same(id[i],id[i-1]);
    102         }
    103         
    104         printf("%lld",Ans);
    105 }
    View Code
  • 相关阅读:
    Java知识体系之基础知识
    002-JavaNIO
    001-四种常见的IO模型
    c/c++面试题(6)运算符重载详解
    c/c++面试题(5)(c++重要的概念详解)
    c/c++面试题(4)字符串翻转/打印任意进制格式/类型转换
    c/c++面试题(3)strcat/strcmp/strlen/strcpy的实现
    c/c++面试题(2)
    c/c++面试题(1)
    cocos2dx 3.0 之 lua 创建类 (二)
  • 原文地址:https://www.cnblogs.com/BearChild/p/6511833.html
Copyright © 2020-2023  润新知