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

2024-09-05 16:58

本文主要是介绍树链剖分 + 后缀数组 - E. Misha and LCP on Tree,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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;
}

这篇关于树链剖分 + 后缀数组 - E. Misha and LCP on Tree的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139542

相关文章

hdu2241(二分+合并数组)

题意:判断是否存在a+b+c = x,a,b,c分别属于集合A,B,C 如果用暴力会超时,所以这里用到了数组合并,将b,c数组合并成d,d数组存的是b,c数组元素的和,然后对d数组进行二分就可以了 代码如下(附注释): #include<iostream>#include<algorithm>#include<cstring>#include<stack>#include<que

hdu 1166 敌兵布阵(树状数组 or 线段树)

题意是求一个线段的和,在线段上可以进行加减的修改。 树状数组的模板题。 代码: #include <stdio.h>#include <string.h>const int maxn = 50000 + 1;int c[maxn];int n;int lowbit(int x){return x & -x;}void add(int x, int num){while

C语言:柔性数组

数组定义 柔性数组 err int arr[0] = {0}; // ERROR 柔性数组 // 常见struct Test{int len;char arr[1024];} // 柔性数组struct Test{int len;char arr[0];}struct Test *t;t = malloc(sizeof(Test) + 11);strcpy(t->arr,

C 语言基础之数组

文章目录 什么是数组数组变量的声明多维数组 什么是数组 数组,顾名思义,就是一组数。 假如班上有 30 个同学,让你编程统计每个人的分数,求最高分、最低分、平均分等。如果不知道数组,你只能这样写代码: int ZhangSan_score = 95;int LiSi_score = 90;......int LiuDong_score = 100;int Zhou

树(Tree)——《啊哈!算法》

树 什么是树?树是一种特殊的图,不包含回路的连通无向树。 正因为树有着“不包含回路”这个特点,所以树就被赋予了很多特性。 一棵树中的任意两个结点有且仅有唯一的一条路径连通。一棵树如果有n个结点,那么它一定恰好有n-1条边。在一棵树中加一条边将会构成一个回路。 一棵树有且只有一个根结点。 没有父结点的结点称为根结点(祖先)。没有子结点的结点称为叶结点。如果一个结点既不是根结点也不是叶

计算数组的斜率,偏移,R2

模拟Excel中的R2的计算。         public bool fnCheckRear_R2(List<double[]> lRear, int iMinRear, int iMaxRear, ref double dR2)         {             bool bResult = true;             int n = 0;             dou

C# double[] 和Matlab数组MWArray[]转换

C# double[] 转换成MWArray[], 直接赋值就行             MWNumericArray[] ma = new MWNumericArray[4];             double[] dT = new double[] { 0 };             double[] dT1 = new double[] { 0,2 };

PHP7扩展开发之数组处理

前言 这次,我们将演示如何在PHP扩展中如何对数组进行处理。要实现的PHP代码如下: <?phpfunction array_concat ($arr, $prefix) {foreach($arr as $key => $val) {if (isset($prefix[$key]) && is_string($val) && is_string($prefix[$key])) {$arr[

Go 数组赋值问题

package mainimport "fmt"type Student struct {Name stringAge int}func main() {data := make(map[string]*Student)list := []Student{{Name:"a",Age:1},{Name:"b",Age:2},{Name:"c",Age:3},}// 错误 都指向了最后一个v// a

码蹄集部分题目(2024OJ赛9.4-9.8;线段树+树状数组)

1🐋🐋配对最小值(王者;树状数组) 时间限制:1秒 占用内存:64M 🐟题目思路 MT3065 配对最小值_哔哩哔哩_bilibili 🐟代码 #include<bits/stdc++.h> using namespace std;const int N=1e5+7;int a[N],b[N],c[N],n,q;struct QUERY{int l,r,id;}que