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相关推荐

  1. hdu 3966(树链剖分+线段树区间更新)

    传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...

  2. HDU 3966-Aragorn's Story 树链剖分+树状数组

    题目链接 题意:有一棵树,每个节点有权值 有三种操作: I c1 c2 k 从节点c1到节点c2的路径上每个节点权值增加k D c1 c2 k 从节点c1到节点c2的路径上每个节点权值减少k Q i ...

  3. 兰州大学第一届 飞马杯 ★★快乐苹果树★★ 树链剖分 + 懒标记 + 树状数组

    传送门 文章目录 题意: 思路: 题意: 思路: 第一次听说树链剖分能在fa[top[i]]fa[top[i]]fa[top[i]]的地方加懒标记,学到了学到了. 首先不能被题目吓住,这个题目仔细剖析 ...

  4. 【LuoguP3038/[USACO11DEC]牧草种植Grass Planting】树链剖分+树状数组【树状数组的区间修改与区间查询】...

    模拟题,可以用树链剖分+线段树维护. 但是学了一个厉害的..树状数组的区间修改与区间查询.. 分割线里面的是转载的: ----------------------------------------- ...

  5. bzoj1146整体二分+树链剖分+树状数组

    其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 1 #include<cstdio> 2 #include< ...

  6. Housewife Wind POJ - 2763 倍增LCA+树状数组 或 树链剖分+线段树

    题目 链接:http://poj.org/problem?id=2763 Language:Default Housewife Wind Time Limit: 4000MS   Memory Lim ...

  7. 2017 ACM/ICPC Asia Regional Shenyang Online Ping Ping Ping 树链剖分+树状数组

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6203 题目大意:给出n+1个节点的树( 3<n<10^4),并给出m对点(m<=50 ...

  8. 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries

    题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv​直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...

  9. BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组

    欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链 ...

最新文章

  1. Windows下R语言环境安装
  2. 图像篡改痕迹检测:Adobe双流Faster R-CNN网络
  3. 外梯度—lhMorpGradientOut
  4. numpy——mgrid
  5. Python3实现快速排序 通俗易懂
  6. adb 更新 android sdk,[转载]安装Android时SDK AVD MANAGER时更新报错的解决办法
  7. ffmpeg 纯静态编译,以及添加自定义库流程摘要
  8. 2019.7.23整理记录以及四道题
  9. 在安卓手机上编写和运行Python 3.x程序
  10. docker加载新的镜像后repository和tag名称都为none的解决方法
  11. contentprovider java_ContentProvider和数据库的区别
  12. 《Shell 脚本学习指南 》 -- 背景知识与入门 [第一、二章]
  13. js中 json对象与json字符串相互转换的几种方式
  14. gitter 卸载_最佳Gitter渠道:材料设计
  15. 苹果手机使用技巧篇:教你完美使用好苹果手机的4个方法
  16. 【论文笔记】From the Detection of Toxic Spans in Online Discuss to the Analysis of Toxic-to-Civil Transfer
  17. beyond compare 3中文乱码
  18. 用python发送put请求
  19. 6、幻灯管理 - 后端功能开发 - 微擎小程序模块应用开发
  20. SimpleDateFormat格式

热门文章

  1. cygwin安装hadoop过程中出现的2个问题
  2. python获取列表中前N大的索引
  3. icop java,java基于spring注解AOP的异常处理的方法
  4. r语言 bsda包_使用R语言creditmodel包进行Vintage分析或留存率分析
  5. 如何根据原理图画封装_生物水处理专用消泡剂是如何根据生物水处理工艺原理进行消泡的?...
  6. python dataframe 计算上下两行的差值_用Python进行数据清洗!
  7. ASP.NET Web Pages – 页面布局简介
  8. 只要有热情和方法就能学好Linux
  9. Linux系统上用Sigil创建和编辑 EPUB 文件
  10. 鸿蒙os上手,Mate40 Pro鸿蒙OS快速上手体验+一点个人看法