树链剖分 + 后缀数组 - E. Misha and LCP on Tree

简介: E. Misha and LCP on Tree  Problem's Link   Mean:  给出一棵树,每个结点上有一个字母。每个询问给出两个路径,问这两个路径的串的最长公共前缀。

E. Misha and LCP on Tree 

Problem's Link


 

Mean: 

给出一棵树,每个结点上有一个字母。每个询问给出两个路径,问这两个路径的串的最长公共前缀。

analyse:

做法:树链剖分+后缀数组.

记录每条链的串,正反都需要标记,组成一个长串.

然后记录每条链对应的串在大串中的位置,对大串求后缀数组,最后询问就是在一些链上的查询。

Time complexity: O(n*logn)

 

view code

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <cstring>
#define SIZE 300005
#define BB 1145143
#define MOD 1000000007
#define BT 20

using namespace std;
typedef long long int ll;

vector < int > vec [ SIZE ];
vector < int > get [ SIZE ];
int par [ SIZE ][ BT ], dep [ SIZE ];
ll hash1 [ SIZE ], hash2 [ SIZE ], rt [ SIZE ];
int nd [ SIZE ], nxt [ SIZE ], id [ SIZE ], pos [ SIZE ];
int n1 [ SIZE ], n2 [ SIZE ];
char str [ SIZE ];
int n , m;

void dfs( int v = 0 , int p =- 1 , int d = 0 , ll h1 = 0 , ll h2 = 0)
{
    par [ v ][ 0 ] =p;
    dep [ v ] = d;
    h1 *=BB;
    hash1 [ v ] = h1 +( str [ v ] - 'a' + 1);
    hash2 [ v ] = h2 +( ll) ( str [ v ] - 'a' + 1) * rt [ d ];
    hash1 [ v ] %= MOD;
    hash2 [ v ] %= MOD;
    nd [ v ] = 1;
    for( int i = 0; i < vec [ v ]. size(); i ++)
    {
        int to = vec [ v ][ i ];
        if( to !=p)
        {
            dfs( to , v , d + 1 , hash1 [ v ], hash2 [ v ]);
            nd [ v ] += nd [ to ];
        }
    }
}
void make()
{
    for( int i = 0; i < BT - 1; i ++)
    {
        for( int j = 0; j <n; j ++)
        {
            if( par [ j ][ i ] ==- 1) par [ j ][ i + 1 ] =- 1;
            else par [ j ][ i + 1 ] = par [ par [ j ][ i ]][ i ];
        }
    }
}
ll get1( int s , int t)
{
    int p = par [ t ][ 0 ];
    return ( hash1 [s ] -(p ==- 1 ? 0 : hash1 [p ] * rt [ dep [s ] - dep [p ]] % MOD) + MOD) % MOD;
}
ll get2( int s , int t)
{
    int p = par [s ][ 0 ];
    return ( hash2 [ t ] -(p ==- 1 ? 0 : hash2 [p ]) + MOD) % MOD;
}
int LCA( int a , int b)
{
    if( dep [ a ] > dep [b ]) swap( a ,b); //dep[a]<=dep[b]
    for( int i = BT - 1; i >= 0; i --)
    {
        if( par [b ][ i ] ==- 1|| dep [ par [b ][ i ]] < dep [ a ]) continue;
       b = par [b ][ i ];
    }
    if( a ==b) return a;
    for( int i = BT - 1; i >= 0; i --)
    {
        if( par [ a ][ i ] != par [b ][ i ])
        {
            a = par [ a ][ i ];
           b = par [b ][ i ];
        }
    }
    return par [ a ][ 0 ];
}
int sz;
void heavy_light( int v = 0 , int p =- 1 , int last =- 1)
{
    bool up = false;
    pos [ v ] = sz;
    id [ v ] = get [ sz ]. size();
    nxt [ v ] = last;
    get [ sz ]. push_back( v);
    for( int i = 0; i < vec [ v ]. size(); i ++)
    {
        int to = vec [ v ][ i ];
        if( to !=p && nd [ to ] * 2 >= nd [ v ])
        {
            heavy_light( to , v , last);
            up = true;
            break;
        }
    }
    if( ! up) sz ++;
    for( int i = 0; i < vec [ v ]. size(); i ++)
    {
        int to = vec [ v ][ i ];
        if( to !=p && nd [ to ] * 2 < nd [ v ])
        {
            heavy_light( to , v , v);
        }
    }
}
int main()
{
    scanf( "%d" , &n);
    scanf( "%s" , & str);
    for( int i = 0; i <n - 1; i ++)
    {
        int a ,b;
        scanf( "%d %d" , & a , &b);
        a --;
       b --;
        vec [ a ]. push_back(b);
        vec [b ]. push_back( a);
    }
    rt [ 0 ] = 1;
    for( int i = 1; i < SIZE; i ++) rt [ i ] = rt [ i - 1 ] *( ll) BB % MOD;
    dfs();
    make();
    heavy_light(); /*
   printf("%d\n",sz);
   for(int i=0;i<sz;i++)
   {
       for(int j=0;j<get[i].size();j++) printf("%d ",get[i][j]);
       puts("");
   }*/
    int m;
    scanf( "%d" , & m);
    for( int i = 0; i < m; i ++)
    {
        int a ,b , c , d;
        scanf( "%d %d %d %d" , & a , &b , & c , & d);
        a --;
       b --;
        c --;
        d --;
        if( str [ a ] != str [ c ])
        {
            puts( "0");
            continue;
        }
        int p = LCA( a ,b ), q = LCA( c , d);
        if( dep [ a ] - dep [p ] > dep [ c ] - dep [ q ])
        {
            swap( a , c);
            swap(b , d);
            swap(p , q);
        }
        int A =b , bef =- 1;
        while( A !=- 1)
        {
            n1 [ pos [ A ]] = bef;
            bef = get [ pos [ A ]][ 0 ];
            A = nxt [ A ];
        }
        int C = d;
        bef =- 1;
        while( C !=- 1)
        {
            n2 [ pos [ C ]] = bef;
            bef = get [ pos [ C ]][ 0 ];
            C = nxt [ C ];
        }
        bool up = true;
        int ret = 1;
        while( a !=p)
        {
            int ta = nxt [ a ];
            if( ta ==- 1|| dep [ ta ] < dep [p ]) ta =p;
            int tc = nxt [ c ];
            if( tc ==- 1|| dep [ tc ] < dep [ q ]) tc = q;
            int la = dep [ a ] - dep [ ta ], lc = dep [ c ] - dep [ tc ];
            int ml = min( la , lc);
            int va = ml == la ? ta: get [ pos [ a ]][ id [ a ] - ml ];
            int vc = ml == lc ? tc: get [ pos [ c ]][ id [ c ] - ml ];
            if( get1( a , va) != get1( c , vc))
            {
                int s =- 1 , e = ml;
                while( e -s > 1)
                {
                    int m =(s + e) / 2;
                    va = get [ pos [ a ]][ id [ a ] - m ];
                    vc = get [ pos [ c ]][ id [ c ] - m ];
                    if( get1( a , va) != get1( c , vc)) e = m;
                    else s = m;
                }
                ret +=s;
                up = false;
                break;
            }
            ret += ml;
            a = va;
            c = vc;
        }
        if( ! up)
        {
            printf( "%d \n " , ret);
            continue;
        }
        while( c != q && a !=b)
        {
            int ta = n1 [ pos [ a ]];
            if( ta ==- 1|| dep [ ta ] > dep [b ]) ta =b;
            int tc = nxt [ c ];
            if( tc ==- 1|| dep [ tc ] < dep [ q ]) tc = q;
            int la = dep [ ta ] - dep [ a ], lc = dep [ c ] - dep [ tc ];
            int ml = min( la , lc);
            int va = ml == la ? ta: get [ pos [ a ]][ id [ a ] + ml ];
            int vc = ml == lc ? tc: get [ pos [ c ]][ id [ c ] - ml ];
            if( get2( a , va) != get1( c , vc) * rt [ dep [ a ]] % MOD)
            {
                int s =- 1 , e = ml;
                while( e -s > 1)
                {
                    int m =(s + e) / 2;
                    va = get [ pos [ a ]][ id [ a ] + m ];
                    vc = get [ pos [ c ]][ id [ c ] - m ];
                    if( get2( a , va) != get1( c , vc) * rt [ dep [ a ]] % MOD) e = m;
                    else s = m;
                }
                ret +=s;
                up = false;
                break;
            }
            ret += ml;
            a = va;
            c = vc;
        }
        if( ! up)
        {
            printf( "%d \n " , ret);
            continue;
        }
        while( a !=b && c != d)
        {
            int ta = n1 [ pos [ a ]];
            if( ta ==- 1|| dep [ ta ] > dep [b ]) ta =b;
            int tc = n2 [ pos [ c ]];
            if( tc ==- 1|| dep [ tc ] > dep [ d ]) tc = d;
            int la = dep [ ta ] - dep [ a ], lc = dep [ tc ] - dep [ c ];
            int ml = min( la , lc);
            int va = ml == la ? ta: get [ pos [ a ]][ id [ a ] + ml ];
            int vc = ml == lc ? tc: get [ pos [ c ]][ id [ c ] + ml ];
            if( get2( a , va) * rt [ dep [ c ]] % MOD != get2( c , vc) * rt [ dep [ a ]] % MOD)
            {
                int s =- 1 , e = ml;
                while( e -s > 1)
                {
                    int m =(s + e) / 2;
                    va = get [ pos [ a ]][ id [ a ] + m ];
                    vc = get [ pos [ c ]][ id [ c ] + m ];
                    if( get2( a , va) * rt [ dep [ c ]] % MOD != get2( c , vc) * rt [ dep [ a ]] % MOD) e = m;
                    else s = m;
                }
                ret +=s;
                up = false;
                break;
            }
            ret += ml;
            a = va;
            c = vc;
        }
        printf( "%d \n " , ret);
    }
    return 0;
}
目录
相关文章
|
7月前
|
测试技术
【动态规划】【状态压缩】LCP04 覆盖
【动态规划】【状态压缩】LCP04 覆盖
|
6月前
|
人工智能 算法 Java
深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。
深度优先搜索(Depth-First Search,DFS)是一种用于遍历或搜索树或图的算法。
|
7月前
|
C++
B. Tree Tag(贪心+树的最长直径)
B. Tree Tag(贪心+树的最长直径)
【LeetCode】BM1 反转链表、NC21 链表内指定区间反转
BM1 反转链表 描述: 给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
53 0
|
算法 程序员
【牛客算法BM2】 链表内指定区间反转
你好,欢迎来到我的博客!作为一名程序员,我经常刷LeetCode题目来提升自己的编程能力。在我的博客里,我会分享一些我自己做过的题目和解题思路,希望能够帮助到大家。今天,我想和大家分享一道挑战性较高的题目,让我们一起来挑战一下吧!作者也是在学习的过程中刷到有意思的题目就会选择与大家分享,并且提供较优解,关于力扣 的文章全部放在博客,如果大家喜欢记得支持作者。🤓
|
机器学习/深度学习
51nod 1405 树的距离之和 (树形dp)
51nod 1405 树的距离之和 (树形dp)
95 0
|
人工智能 vr&ar
SPOJ - COT Count on a tree(主席树 LCA)
SPOJ - COT Count on a tree(主席树 LCA)
99 0
UPC Graph (最小生成树 || 并查集+二分)
UPC Graph (最小生成树 || 并查集+二分)
94 0
CF960F. Pathwalks (树上二维LIS 线段树 动态开点树状数组)
CF960F. Pathwalks (树上二维LIS 线段树 动态开点树状数组)
106 0
PTA -7-51 两个有序链表序列的合并(C++)
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2合并后的新的非降序链表S3。 输入格式: 输入分两行,分别在每行给出由若干个正整数构成的非降序序列,用−1表示序列的结尾(−1不属于这个序列)。数字用空格间隔。 输出格式: 在一行中输出合并后新的非降序链表,数字间用空格分开,结尾不能有多余空格;若新链表为空,输出NULL。 输入样例: 1 3 5 -1 2 4 6 8 10 -1 输出样例: 1 2 3 4 5 6 8 10
581 0