CF 504E Misha and LCP on Tree——后缀数组+树链剖分
题目:http://codeforces.com/contest/504/problem/E
树链剖分,把重链都接起来,且把每条重链的另一种方向的也都接上,在这个 2*n 的序列上跑后缀数组。
对于询问,把两条链拆成一些重链的片段,然后两个指针枚举每个片段,用后缀数组找片段与片段的 LCP ,直到一次 LCP 的长度比两个片段的长度都小,说明两条链的 LCP 截止于此。
把重链放到序列上其实就是把 dfn 作为序列角标。
不太会实现,就借鉴(抄)了别人的代码。之后要多多回顾。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=3e5+,M=N<<,K=;
int n,hd[N],xnt,to[M],nxt[M],tim,dfn1[N],dfn2[N],siz[N],son[N],dep[N],top[N],fa[N];
int sa[M],rk[M],tp[M],tx[M],ht[M][K],bin[K],lg[M];
char ch[N],s[M];
struct Node{int l,len;}a1[N],a2[N];
int Mn(int a,int b){return a<b?a:b;}
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='') ret=ret*+ch-'',ch=getchar();
return fx?ret:-ret;
}
void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;}
void dfs(int cr,int f)
{
siz[cr]=;dep[cr]=dep[f]+;fa[cr]=f;
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=f)
{
dfs(v,cr);siz[cr]+=siz[v];
if(siz[v]>siz[son[cr]])son[cr]=v;
}
}
void dfsx(int cr,int fa)
{
dfn1[cr]=++tim;
if(son[cr])top[son[cr]]=top[cr],dfsx(son[cr],cr);
for(int i=hd[cr],v;i;i=nxt[i])
if((v=to[i])!=fa&&v!=son[cr])
top[v]=v,dfsx(v,cr);
}
void Rsort(int n,int nm)
{
for(int i=;i<=nm;i++)tx[i]=;
for(int i=;i<=n;i++)tx[rk[i]]++;
for(int i=;i<=nm;i++)tx[i]+=tx[i-];
for(int i=n;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
}
void get_sa(int n)
{
int nm=;
for(int i=;i<=n;i++)tp[i]=i,rk[i]=s[i];
Rsort(n,nm);
for(int k=;k<=n;k<<=)
{
int tot=;
for(int i=n-k+;i<=n;i++)tp[++tot]=i;
for(int i=;i<=n;i++)
if(sa[i]>k)tp[++tot]=sa[i]-k;
Rsort(n,nm);
swap(rk,tp);nm=;rk[sa[]]=;
for(int i=,u,v;i<=n;i++)
{
u=sa[i]+k;v=sa[i-]+k;if(u>n)u=;if(v>n)v=;
rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[u]==tp[v])?nm:++nm;//rk[sa[i]]
}
if(nm==n)break;
}
}
void get_ht(int n)
{
int k=,j;
for(int i=;i<=n;i++)//index of s[]
{
for(j=sa[rk[i]-],k?k--:;i+k<=n&&j+k<=n&&s[i+k]==s[j+k];k++);
ht[rk[i]][]=k;//rk[i]
}
lg[]=;for(int i=;i<=n;i++)lg[i]=lg[i>>]+;
bin[]=;for(int i=;i<=lg[n];i++)bin[i]=bin[i-]<<; for(int j=;j<=lg[n];j++)
for(int i=;i+bin[j]-<=n;i++)
ht[i][j]=Mn(ht[i][j-],ht[i+bin[j-]][j-]);//+bin[j-1]!
}
int get_lca(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
void get_a(int x,int y,int &tot,Node *a)
{
tot=;int lca=get_lca(x,y);
while(dep[top[x]]>=dep[lca])
a[++tot]=(Node){dfn2[x],dfn2[top[x]]-dfn2[x]+},x=fa[top[x]];
if(dep[x]>=dep[lca])a[++tot]=(Node){dfn2[x],dfn2[lca]-dfn2[x]+};
int bj=tot;
while(dep[top[y]]>dep[lca])
a[++tot]=(Node){dfn1[top[y]],dfn1[y]-dfn1[top[y]]+},y=fa[top[y]];
if(dep[y]>dep[lca])a[++tot]=(Node){dfn1[son[lca]],dfn1[y]-dfn1[son[lca]]+};
reverse(a+bj+,a+tot+);
}
int get_ans(int l,int r)//l,r:index of s[]
{
if(l==r)return (n<<)-(l-);
l=rk[l]; r=rk[r]; if(l>r)swap(l,r);//rk[]!
int d=lg[r-l];
return Mn(ht[l+][d],ht[r-bin[d]+][d]);
}
int main()
{
n=rdn();scanf("%s",ch+);
for(int i=,u,v;i<n;i++)
{
u=rdn();v=rdn();add(u,v);add(v,u);
}
dfs(,);top[]=;dfsx(,);
for(int i=,j=(n<<)+;i<=n;i++)dfn2[i]=j-dfn1[i],s[dfn1[i]]=s[dfn2[i]]=ch[i]-'a'+;
get_sa(n<<);get_ht(n<<);
int Q=rdn(),a,b,c,d,nm1,nm2;
while(Q--)
{
a=rdn();b=rdn();c=rdn();d=rdn();
get_a(a,b,nm1,a1);get_a(c,d,nm2,a2);
int p1=,p2=,st1=,st2=,ans=;
while(p1<=nm1&&p2<=nm2)
{
int len=get_ans(a1[p1].l+st1,a2[p2].l+st2);
int d=Mn(a1[p1].len-st1,a2[p2].len-st2);
len=Mn(len,d);
ans+=len;st1+=len;st2+=len;
if(len<d)break;
if(st1==a1[p1].len)st1=,p1++;
if(st2==a2[p2].len)st2=,p2++;
}
printf("%d\n",ans);
}
return ;
}
CF 504E Misha and LCP on Tree——后缀数组+树链剖分的更多相关文章
- CF504E Misha and LCP on Tree 后缀自动机+树链剖分+倍增
		
求树上两条路径的 LCP (树上每个节点代表一个字符) 总共写+调了6个多小时,终于过了~ 绝对是我写过的最复杂的数据结构了 我们对这棵树进行轻重链剖分,然后把所有的重链分正串,反串插入到广义后缀自动 ...
 - CF 504E	Misha and LCP on Tree(树链剖分+后缀数组)
		
题目链接:http://codeforces.com/problemset/problem/504/E 题意:给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. ...
 - Water Tree CodeForces 343D 树链剖分+线段树
		
Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...
 - CF G. Indie Album 广义后缀自动机+树链剖分+线段树合并
		
这里给出一个后缀自动机的做法. 假设每次询问 $t$ 在所有 $s$ 中的出现次数,那么这是非常简单的: 直接对 $s$ 构建后缀自动机,随便维护一下 $endpos$ 大小就可以. 然而,想求 $t ...
 - Codeforces Round #329 (Div. 2) D. Happy Tree Party LCA/树链剖分
		
D. Happy Tree Party Bogdan has a birthday today and mom gave him a tree consisting of n vertecie ...
 - [POJ3237]Tree解题报告|树链剖分|边剖
		
关于边剖 之前做的大多是点剖,其实转换到边剖非常简单. 我的做法是每个点的点权记录其到父亲节点的边的边权. 只要solve的时候不要把最上面的点记录在内就可以了. Tree Description Y ...
 - Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)
		
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
 - BZOJ3637 Query on a tree VI(树链剖分+线段树)
		
考虑对于每一个点维护子树内与其连通的点的信息.为了换色需要,记录每个点黑白两种情况下子树内连通块的大小. 查询时,找到深度最浅的同色祖先即可,这可以比较简单的树剖+线段树乱搞一下(似乎就是qtree3 ...
 - [LuoguU41039]PION后缀自动机 树链剖分+动态开点线段树
		
链接 刚开始看出题人题解都吓蒙掉了,还以为是什么难题,结果就一板子题 思路:对每一个文件名开一棵线段树,然后树剖即可 #include<bits/stdc++.h> #define REP ...
 
随机推荐
- 什么是webhook
			
什么是webhook 翻译,原文地址:https://sendgrid.com/blog/webhook-vs-api-whats-difference/ 一.概述 Webhook是一个API概念,并 ...
 - redhat 6.8 配置yum源
			
一般安装好redhat后,不能注册的话,不能使用系统自带的yum源.但是我们可以自己配置yum源来解决这一问题.下面介绍下redhat配置163yum源. 1. 检查是否安装yum包 rpm -qa ...
 - LeetCode Weekly Contest 23
			
LeetCode Weekly Contest 23 1. Reverse String II Given a string and an integer k, you need to reverse ...
 - UVA 10288 Coupons (概率)
			
题意:有n种纸片无限张,随机抽取,问平均情况下抽多少张可以保证抽中所有类型的纸片 题解:假设自己手上有k张,抽中已经抽过的概率为 s=k/n:那抽中下一张没被抽过的纸片概率为 (再抽一张中,两张中,三 ...
 - linux 终端分屏命令
			
比如:某文件夹下有文件:vector.cc, substr.cc 1.使用vim命令打开任意一个文件:vim vector.cc打开第一个文件.如下图所示: 2.按:"Esc"键 ...
 - Oracle递归查询与常用分析函数
			
最近学习oracle的一些知识,发现自己sql还是很薄弱,需要继续学习,现在总结一下哈. (1)oracle递归查询 start with ... connect by prior ,至于是否向上查 ...
 - .net 数据脱敏代码实现
			
方案一: DTO中处理: private string idNumber; /// <summary> /// 身份证号码 /// </summary> [Column(&qu ...
 - JDK_环境变量
			
1. 在系统环境变量中设置: ClASSPATH中输入: ".;C:\Program Files\Java\jdk1.7.0_07\jre\lib\rt.jar;"//java的安 ...
 - Nginx+Tomcat+Redis实现集群搭建
			
背景: 最近几天一直在琢磨Nginx反向代理以及使用Redis保存session,因为本人对java开发比较熟悉,所以在闲暇之余将公司的一个系统在虚拟机上搭建一个集群.特此总结过程. 一.需要使用的一 ...
 - mysql 转移数据目录
			
由于MySql的数据库文件和日志文件比较大,导致磁盘空间不够,在添加新的磁盘之后,需要把MySql的数据转移到新挂载的目录下. 1.停止MySql服务: /etc/rc.d/init.d/mysql ...