大概是四节课写代码,三节课debug,七个长相差不多的dfs穿插其中……
好了不吐槽了;
题意:
给定一棵点上有字母的树,和一个母串
求树上点两两之间 N2N^2 条路径在母串中匹配次数和

这里采用的基本是《CTSC2010珠宝商新解》–许昊然的做法
首先考虑两种不同的暴力:
1.枚举端点dfs,SAM上跑转移O(N2)O(N^2)
2.这个暴力比较特殊;
考虑一个作为路径lca的点A,则我们可以尝试用A子树中两条“半路径”拼出原路径;
不妨设A上字母为ii,则需 (x,i) , (i,y) 构成(x,y);
这个问题可以通过在正反串的后缀树上打标记,再下放至叶子就可以合并了;
单次O(N)O(N),总的O(N2)O(N^2)

那么正解肯定是把他们拼起来啦;
解法1喜欢n较小的情况(当然soas解法2);
解法2单次复杂度与子树大小无关的;
借助点分治这个平台,二者便可巧妙结合:

在点分治中,如果子树大小小于N−−√\sqrt{N} 便采用解法1,并停止递归;
如果子树大小大于N−−√\sqrt{N} 便采用解法2;

其中由于第一步子树之间相互独立,则最差NN−−√N\sqrt{N}
第二步可以证明大小大于N−−√\sqrt{N} 的分治子树不超过N−−√\sqrt{N}个,故也是NN−−√N\sqrt{N}

但参拜lct1999的题解得知论文有一个细节处理不当
即在分治去重中也是应该依据子树大小判断解法的

嗯…后缀树怎么求?
一般的字符集小的前提下:SAM–>后缀树–>SA

附上写过最丑的代码…..

#include<bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;i++)
#define rep2(i,k,n) for(int i=k;i>=n;i--)
#define pa pair<int,int>
#define mk make_pair
#define fr first
#define sc second
using namespace std;
typedef long long ll;
const int N=1e5+7;
const int inf=0x3f3f3f3f;
struct tu{struct E{int to,next;E(int to=0,int next=0):to(to),next(next){}}edge[N<<1];int head[N],tot;void init(){tot=0;}void add(int x,int y){edge[++tot]=E(y,head[x]);head[x]=tot;}
}T;
int n,m;
struct machine{tu tree;int tot,fa[N],ch[N][26],len[N],val[N],nod[N],p,last,sz[N],a[N],c[N],rk[N],q[N],mx[N];char s[N];void init(){last=p=tot=0;}void extend(int c,int pos){int x;p=last,last=x=++tot;len[x]=len[p]+1;nod[x]=sz[x]=1;mx[x]=pos;for(;!ch[p][c];p=fa[p])ch[p][c]=x;if(ch[p][c]!=x){int q=ch[p][c];if(len[p]+1==len[q]){fa[x]=q;}else{int nq=++tot;len[nq]=len[p]+1;fa[nq]=fa[q];memcpy(ch[nq],ch[q],sizeof(ch[q]));fa[q]=fa[x]=nq;for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;}}}void build(){rep(i,1,m)extend(s[i]-'a',i);}void build_tree(){tree.init();rep(i,1,tot)tree.add(fa[i],i);memset(c,0,sizeof(c));rep(i,1,tot)c[len[i]]++;rep(i,1,tot)c[i]+=c[i-1];rep(i,1,tot)rk[i]=c[len[i]]--;rep(i,1,tot)q[rk[i]]=i;rep2(i,tot,1)sz[fa[q[i]]]+=sz[q[i]],mx[fa[q[i]]]=max(mx[fa[q[i]]],mx[q[i]]);}pa trans(pa x,char c){int pos=x.fr;int now=x.sc;int l=mx[pos]-len[pos]+1;int r=mx[pos]-len[fa[pos]];int who=r-now;if(who>=l && pos){if(s[who]==c)return mk(pos,now+1);else return mk(-1,-1);}else{for(int i=tree.head[pos];i;i=tree.edge[i].next){int v=tree.edge[i].to;r=mx[v]-len[fa[v]];if(s[r]==c)return mk(v,1);}return mk(-1,-1);}}void mem(){memset(val,0,sizeof(val));}void push_down(){rep(i,1,tot)for(int j=tree.head[q[i]];j;j=tree.edge[j].next){int v=tree.edge[j].to;val[v]+=val[q[i]];}memset(a,0,sizeof(a));rep(i,1,tot)if(nod[i])a[len[i]]=val[i];}
}t1,t2;
int sz[N],mx[N],vis[N],root,S,Q,fa[N];
ll Ans=0,tmp;
char V[N];
void getrt(int x,int f){sz[x]=1,mx[x]=0;for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(!vis[v] && v!=f){getrt(v,x);mx[x]=max(mx[x],sz[v]);sz[x]+=sz[v];}}mx[x]=max(mx[x],S-sz[x]);if(mx[x]<mx[root])root=x;
}
void dfs3_1(int x,int f,pa now){now=t1.trans(now,V[x]);if(now.fr==-1)return;t1.val[now.fr]++;for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(v!=f && !vis[v])dfs3_1(v,x,now);}
}
void dfs3_2(int x,int f,pa now){now=t2.trans(now,V[x]);if(now.fr==-1)return;t2.val[now.fr]++;for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(v!=f && !vis[v])dfs3_2(v,x,now);}
}
ll sol1(int x,int f,pa now1,pa now2){t1.mem();t2.mem();if(now1.fr==-1 || now2.fr==-1)return 0;dfs3_1(x,f,now1);dfs3_2(x,f,now2);t1.push_down();t2.push_down();ll ans=0;rep(i,1,m)ans+=1ll*t1.a[i]*t2.a[m-i+1];return ans;
}
void dfs5(int x,int f,int an,int now,int ok){now=t1.ch[now][V[x]-'a'];if(!now)return;if(x==an){now=t1.ch[now][V[fa[x]]-'a'];if(!now)return;now=t1.ch[now][V[x]-'a'];if(!now)return;ok=1;f=0;}if(!ok)dfs5(fa[x],x,an,now,ok);else{tmp+=t1.sz[now];for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(v!=f && !vis[v] && v!=fa[x])dfs5(v,x,an,now,ok);}}
}
void dfs4(int x,int f,int an){dfs5(x,0,an,0,0);for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(v!=f && !vis[v])dfs4(v,x,an);}
}
ll sol2(int x,int f){tmp=0;dfs4(x,f,x);return tmp;
}
void way1(int x){Ans+=sol1(x,0,mk(0,0),mk(0,0));for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(!vis[v]){if(sz[v]>Q){Ans-=sol1(v,x,t1.trans(mk(0,0),V[x]),t2.trans(mk(0,0),V[x]));}else{Ans-=sol2(v,x);}}}
}
void dfs2(int x,int f,int now){now=t1.ch[now][V[x]-'a'];if(!now)return;tmp+=t1.sz[now];for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(v!=f && !vis[v])dfs2(v,x,now);}
}
void dfs(int x,int f){dfs2(x,0,0);for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(v!=f && !vis[v])dfs(v,x);}
}
void way2(int x){tmp=0;dfs(x,0);
}
void Dfs(int x,int f){fa[x]=f;sz[x]=1;for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(v!=f && !vis[v]){Dfs(v,x);sz[x]+=sz[v];}}
}
void go(int x){if(sz[x]<=Q){way2(x);Ans+=tmp;}else {vis[x]=1;Dfs(x,0);way1(x);for(int i=T.head[x];i;i=T.edge[i].next){int v=T.edge[i].to;if(!vis[v]){S=sz[v],root=0,getrt(v,x);go(root);}}}
}
void solve(){mx[0]=inf;S=n,root=0,getrt(1,0);go(root);}
int main(){scanf("%d%d",&n,&m);Q=sqrt(n)+1;int x,y;T.init();rep(i,1,n-1){scanf("%d%d",&x,&y);T.add(x,y);T.add(y,x);}scanf("%s%s",V+1,t1.s+1);t1.init();t2.init();memcpy(t2.s,t1.s,sizeof(t1.s));rep(i,1,m>>1)swap(t2.s[i],t2.s[m-i+1]);t1.build();t2.build();t1.build_tree();t2.build_tree();solve();printf("%lld\n",Ans);
}

bzoj1921 CTSC2010 jewelry相关推荐

  1. [BZOJ1921] [CTSC2010]珠宝商

    Description Input 第一行包含两个整数 N,M,表示城市个数及特征项链的长度. 接下来的N-1 行, 每行两个整数 x,y, 表示城市 x 与城市 y 有直接道路相连.城市由1~N进行 ...

  2. bzoj1921: [Ctsc2010]珠宝商

    暴毙选手又被zo老师D费了 暴力是n^2的都会 有另一个点分的做法,就是看成两条链,然后在后缀树上跑,找到对应原串位置拼起来,是n*(logn+m) 然后就根号分治,树的大小超过阈值就点分,小于就暴力 ...

  3. bzoj1921 [CTSC2010]珠宝商 SAM+后缀树+点分治

    Description 有一棵n个节点的树和一个长度为m的字符串S,树上每个节点有一个字符.问对于任意的有序数对(x,y),从x到y路径组成的字符串在S中出现次数的和. n,m≤5⋅104n,m\le ...

  4. BZOJ1921: [Ctsc2010]珠宝商(点分治+SAM)

    传送门 题解: 点分治,如果点数≥n\ge \sqrt{n}≥n​,则结合后缀树O(sze+m)O(sze+m)O(sze+m)处理出每个位置的开始,结束点并统计答案.否则从每个点开始暴力扩展路径. ...

  5. 【BZOJ1921】【CTSC2010】珠宝商(点分治,后缀自动机)

    [BZOJ1921][CTSC2010]珠宝商(点分治,后缀自动机) 题面 洛谷 BZOJ权限题 题解 如果要我们做暴力,显然可以以某个点为根节点,然后把子树\(dfs\)一遍,建出特征串的\(SAM ...

  6. 【CTSC2010】珠宝商(SAM)(点分治)(根号分治)

    传送门 给你一棵树,树上每个点有字符,询问所有树上路径形成的字符串在给定模式串中一共出现了几次.在模式串中不同位置出现要多次计算. 题解: 好题啊. 树上路径统计类的问题显然考虑的一般就是链分治和点分 ...

  7. bzoj 1921: [Ctsc2010]珠宝商

    题意: 给一棵树,每个点上有一个字母,问对于所有(x,y),求x到y的路径所组成的字符串在S中出现次数的和. 题解: 先上题解:begined CTSC2010 珠宝商新解 然后说说个人的垃圾理解. ...

  8. [CTSC2010]珠宝商(点分治+根号分治+后缀自动机)

    [CTSC2010]珠宝商 洛谷题目传送门 简要题意 给定一颗nnn个节点的树,和一个长度为mmm的模式串SSS 树上每个节点都有一个字符 求树上所有路径的点的字符拼成的字符串在SSS中的出现次数之和 ...

  9. P4218 [CTSC2010]珠宝商

    P4218 [CTSC2010]珠宝商 神题... 可以想到点分治,细节不写了... (学了个新姿势,sam可以在前面加字符 但是一次点分治只能做到\(O(m)\),考虑\(\sqrt n\)点分治, ...

最新文章

  1. jQuery中的.bind()、.live()和.delegate()之间区别分析
  2. ElementUI中el-table-column的type为selection时选择框旁边有个点
  3. [WinCE版凯立德]2013夏季版地图2E21J0D更新下载(9.8增加2E23J0D分省地图)
  4. 真正掌握vuex的使用方法(六)
  5. 华为手机媒体音量自动静音_华为手机还能自动清理垃圾,怪不得手机越用越流畅,学到了...
  6. Doris之数据划分(全面)
  7. mysql基础之数据库变量(参数)管理
  8. 自学TP5源码(一)
  9. 并发控制中存在问题及解决方案
  10. 关于linux下的iptables 的浅析命令和了解
  11. win7设置固定IP重启后无法上网,ipconfig显示为自动配置IPV4 169.254的地址
  12. Java的对象序列化之serialVersionUID问题
  13. R语言书籍学习02 《R语言数据分析、挖掘建模与可视化》-第一章 R语言必备基础知识
  14. 机器学习笔记 - 探索性数据分析(EDA) 学习进阶
  15. LightOj 1336(Sigma Function)
  16. 计算日期间隔,以XX年XX月XX日格式显示
  17. linux释放cpu命令,linux内存清理和释放命令
  18. integer conversion resulted in a change of sign
  19. JavaScript的对象、属性与方法
  20. vue - vue使用腾讯api进行定位获取,绘制地图、标点、搜索、路线规划

热门文章

  1. java用密码连接路由器_无线路由器与交换机配合使用,图解
  2. 设计模式(八)之抽象工厂模式
  3. eggjs validate no function 解决方案
  4. motan源码分析六:客户端与服务器的通信层分析
  5. mint ui tab html,Vue Mint UI tabbar切换
  6. NASM实现Helloworld
  7. Nasm汇编GDB调试
  8. 【无标题】HTML使用西瓜视频播放监控
  9. 某TMD公司iOS高级工程师面试回忆
  10. php predis password,Redis Cluster 已运行的Redis集群 设置密码 Predis 连接