1A真舒服。

喜闻乐见的树链剖分+SA。

一个初步的想法就是用树链剖分,把两个字符串求出然后hash+二分求lcp。。。不存在的。

因为考虑到这个字符串是有序的,我们需要把每一条重链对应的字符串和这个重链反过来对应的字符串拼起来构成一个新的字符串。我们用树链剖分拼出两个字符串。用树剖拼出的这两个字符串,一定是重链拼成的字符串上一个一个区间,我们记录这些区间的左右端点。然后我们就是要一个一个处理区间。求两个区间对应字符串的lcp,我们直接上SA+ST表就行,求出lcp之后就在这些区间上分情况讨论,然后就结束了。

具体看代码,太丑了也看不出来什么。

#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=601000;
int cnt,head[N];
int size[N],fa[N],dep[N],dfn[N],top[N],tot,son[N];
int s[N],id[N][2],cn,Top[N];
int sa[N],x[N],y[N],len,rk[N],height[N],m,mn[N][20],c[N];
int L[N][2],R[N][2],NUM[N],Num[N],n;
char S[N];
struct edge{
int to,nxt;
}e[N];
void add(int u,int v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs1(int u,int f){
size[u]=1;
fa[u]=f;
dep[u]=dep[f]+1;
int maxson=-1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==f)continue;
dfs1(v,u);
if(size[v]>maxson){
maxson=size[v];
son[u]=v;
}
size[u]+=size[v];
}
}
void dfs2(int u,int tp){
dfn[u]=++tot;
top[u]=tp;
if(son[u])dfs2(son[u],tp);
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[u]||v==son[u])continue;
Top[++cn]=v;
dfs2(v,v);
}
}
void build(int u){
s[++len]=S[u];
id[dfn[u]][0]=len;
if(son[u]==0){
id[dfn[u]][0]=len;
s[++len]=S[u];
id[dfn[u]][1]=len;
return;
}
build(son[u]);
s[++len]=S[u];
id[dfn[u]][1]=len;
}
void get_sa(){
for(int i=1;i<=len;i++)c[x[i]=s[i]]++;
for(int i=1;i<=m;i++)c[i]+=c[i-1];
for(int i=len;i>=1;i--)sa[c[x[i]]--]=i;
for(int k=1;k<=len;k<<=1){
int num=0;
for(int i=len-k+1;i<=len;i++)y[++num]=i;
for(int i=1;i<=len;i++)if(sa[i]>k)y[++num]=sa[i]-k;
for(int i=1;i<=m;i++)c[i]=0;
for(int i=1;i<=len;i++)c[x[i]]++;
for(int i=1;i<=m;i++)c[i]+=c[i-1];
for(int i=len;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
for(int i=1;i<=len;i++)swap(x[i],y[i]);
x[sa[1]]=1;num=1;
for(int i=2;i<=len;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
if(num==len)break;
m=num;
}
}
void get_height(){
int k=0;
for(int i=1;i<=len;i++)rk[sa[i]]=i;
for(int i=1;i<=len;i++){
if(rk[i]==1)continue;
if(k)k--;
int j=sa[rk[i]-1];
while(i+k<=len&&j+k<=len&&s[i+k]==s[j+k])k++;
height[rk[i]]=k;
}
}
void pre_work(){
for(int i=1;i<=len;i++)mn[i][0]=height[i];
int Len=log2(len);
for(int j=1;j<=Len;j++)
for(int i=1;i+(1<<j)-1<=len;i++)
mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]);
}
int get_lcp(int l,int r){
if(l>r)swap(l,r);
l++;
if(l>r)return 1e9;
int Len=log2(r-l+1);
return min(mn[l][Len],mn[r-(1<<Len)+1][Len]);
}
void work(int x,int y,int k){
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]]){
Num[k]++;
L[Num[k]][k]=id[dfn[x]][1];
R[Num[k]][k]=id[dfn[top[x]]][1];
x=fa[top[x]];
}
else{
NUM[k]--;
L[NUM[k]][k]=id[dfn[top[y]]][0];
R[NUM[k]][k]=id[dfn[y]][0];
y=fa[top[y]];
}
}
if(dep[x]>dep[y]){
Num[k]++;
L[Num[k]][k]=id[dfn[x]][1];
R[Num[k]][k]=id[dfn[y]][1];
}
else{
NUM[k]--;
L[NUM[k]][k]=id[dfn[x]][0];
R[NUM[k]][k]=id[dfn[y]][0];
}
}
void calc(){
int now0=1,now1=1;
int tmp=0;
while(now0<=n&&now1<=n){
if(now0>Num[0]&&now0<NUM[0])now0=NUM[0];
if(now1>Num[1]&&now1<NUM[1])now1=NUM[1];
if(now0>n||now1>n)break;
int LL=min(min(R[now0][0]-L[now0][0]+1,R[now1][1]-L[now1][1]+1),get_lcp(rk[L[now0][0]],rk[L[now1][1]]));
L[now0][0]=L[now0][0]+LL;
L[now1][1]=L[now1][1]+LL;
tmp+=LL;
if(L[now0][0]<=R[now0][0]&&L[now1][1]<=R[now1][1])break;
if(L[now0][0]>R[now0][0])now0++;
if(L[now1][1]>R[now1][1])now1++;
}
printf("%d\n",tmp);
}
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum*f;
}
int main(){
n=read();
scanf("%s",S+1);
for(int i=1;i<n;i++){
int u=read(),v=read();
add(u,v);add(v,u);
}
dfs1(1,0);cn=1;Top[1]=1;dfs2(1,1);
for(int i=1;i<=cn;i++)build(Top[i]);
m=122;
get_sa();get_height();pre_work();
m=read();
int a,b,c,d;
while(m--){
a=read();b=read();
c=read();d=read();
Num[0]=Num[1]=0;
NUM[0]=NUM[1]=n+1;
work(a,b,0);work(c,d,1);
calc();
}
return 0;
}

CF504E Misha and LCP on Tree(树链剖分+后缀树组)的更多相关文章

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

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

  2. Aizu 2450 Do use segment tree 树链剖分+线段树

    Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...

  3. 【POJ3237】Tree(树链剖分+线段树)

    Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...

  4. POJ3237 Tree 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...

  5. 【CF725G】Messages on a Tree 树链剖分+线段树

    [CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息 ...

  6. 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, ...

  7. Water Tree CodeForces 343D 树链剖分+线段树

    Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...

  8. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  9. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

随机推荐

  1. getattibute 与 getparameter区别

    1.getAttribute是取得jsp中 用setAttribute设定的attribute 2.parameter得到的是string:attribute得到的是object  3.request ...

  2. There are multiple modules with names that only differ in casing.

    client?4c0e:153 ./src/components/Paginate.vue There are multiple modules with names that only differ ...

  3. [Codeforces 226E]Noble Knight's Path

    题目大意:有一棵n个节点的树,m年.初始每个节点都有.每天有如下操作:1. 给定c,让c没有(c只可能没有一次).2. 给定s,t,k,y,求从第y+1年到现在(即忽略y+1年之前的操作1),s到t的 ...

  4. 【Paper Reading】Deep Supervised Hashing for fast Image Retrieval

    what has been done: This paper proposed a novel Deep Supervised Hashing method to learn a compact si ...

  5. oc基础知识

    只在@interface中定义变量的话,你所定义的变量只能在当前的类中访问,在其他类中是访问不了的:而用@property声明的变量可以在外部访问. 用了@property去声明的变量,可以使用“se ...

  6. VUE:class与style强制绑定

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. linux内核(三)文件系统

    1.为什么需要根文件系统 (1)init进程的应用程序在根文件系统上(2)根文件系统提供了根目录/(3)内核启动后的应用层配置(etc目录)在根文件系统上.几乎可以认为:发行版=内核+rootfs(4 ...

  8. 使用jmap和MAT分析JVM堆内存

    http://blog.csdn.net/alli0968/article/details/52460008

  9. CSS学习(五)

    导航栏 熟练使用导航栏,对于任何网站都非常重要. 使用CSS你可以转换成好看的导航栏而不是枯燥的HTML菜单. 导航栏=链接列表 作为标准的HTML基础一个导航栏是必须的.在我们的例子中我们将建立一个 ...

  10. nyoj--1237--最大岛屿(dfs+数据处理)

    最大岛屿 时间限制:1000 ms  |  内存限制:65535 KB 难度: 描述 神秘的海洋,惊险的探险之路,打捞海底宝藏,激烈的海战,海盗劫富等等.加勒比海盗,你知道吧?杰克船长驾驶着自己的的战 ...