树链剖分 + 后缀数组 - 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 <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相关推荐
- hdu 3966(树链剖分+线段树区间更新)
传送门:Problem 3966 https://www.cnblogs.com/violet-acmer/p/9711441.html 学习资料: [1]线段树区间更新:https://blog.c ...
- HDU 3966-Aragorn's Story 树链剖分+树状数组
题目链接 题意:有一棵树,每个节点有权值 有三种操作: I c1 c2 k 从节点c1到节点c2的路径上每个节点权值增加k D c1 c2 k 从节点c1到节点c2的路径上每个节点权值减少k Q i ...
- 兰州大学第一届 飞马杯 ★★快乐苹果树★★ 树链剖分 + 懒标记 + 树状数组
传送门 文章目录 题意: 思路: 题意: 思路: 第一次听说树链剖分能在fa[top[i]]fa[top[i]]fa[top[i]]的地方加懒标记,学到了学到了. 首先不能被题目吓住,这个题目仔细剖析 ...
- 【LuoguP3038/[USACO11DEC]牧草种植Grass Planting】树链剖分+树状数组【树状数组的区间修改与区间查询】...
模拟题,可以用树链剖分+线段树维护. 但是学了一个厉害的..树状数组的区间修改与区间查询.. 分割线里面的是转载的: ----------------------------------------- ...
- bzoj1146整体二分+树链剖分+树状数组
其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 1 #include<cstdio> 2 #include< ...
- Housewife Wind POJ - 2763 倍增LCA+树状数组 或 树链剖分+线段树
题目 链接:http://poj.org/problem?id=2763 Language:Default Housewife Wind Time Limit: 4000MS Memory Lim ...
- 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 ...
- 树链剖分 or 根号分治 + dfs序 + 树状数组 ---- CF1254 D. Tree Queries
题目链接 题目大意: 问题转化: 很容易发现:假设修改的节点是vvv. 1.vvv的子树sonvson_vsonv直接加上(n−size[sonv])n×d\frac{(n-size[son_v]) ...
- BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组
欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链 ...
最新文章
- Windows下R语言环境安装
- 图像篡改痕迹检测:Adobe双流Faster R-CNN网络
- 外梯度—lhMorpGradientOut
- numpy——mgrid
- Python3实现快速排序 通俗易懂
- adb 更新 android sdk,[转载]安装Android时SDK AVD MANAGER时更新报错的解决办法
- ffmpeg 纯静态编译,以及添加自定义库流程摘要
- 2019.7.23整理记录以及四道题
- 在安卓手机上编写和运行Python 3.x程序
- docker加载新的镜像后repository和tag名称都为none的解决方法
- contentprovider java_ContentProvider和数据库的区别
- 《Shell 脚本学习指南 》 -- 背景知识与入门 [第一、二章]
- js中 json对象与json字符串相互转换的几种方式
- gitter 卸载_最佳Gitter渠道:材料设计
- 苹果手机使用技巧篇:教你完美使用好苹果手机的4个方法
- 【论文笔记】From the Detection of Toxic Spans in Online Discuss to the Analysis of Toxic-to-Civil Transfer
- beyond compare 3中文乱码
- 用python发送put请求
- 6、幻灯管理 - 后端功能开发 - 微擎小程序模块应用开发
- SimpleDateFormat格式
热门文章
- cygwin安装hadoop过程中出现的2个问题
- python获取列表中前N大的索引
- icop java,java基于spring注解AOP的异常处理的方法
- r语言 bsda包_使用R语言creditmodel包进行Vintage分析或留存率分析
- 如何根据原理图画封装_生物水处理专用消泡剂是如何根据生物水处理工艺原理进行消泡的?...
- python dataframe 计算上下两行的差值_用Python进行数据清洗!
- ASP.NET Web Pages – 页面布局简介
- 只要有热情和方法就能学好Linux
- Linux系统上用Sigil创建和编辑 EPUB 文件
- 鸿蒙os上手,Mate40 Pro鸿蒙OS快速上手体验+一点个人看法