Description

Input

第一行包含两个整数 N,M,表示城市个数及特征项链的长度。 接下来的N-1 行, 每行两个整数 x,y, 表示城市 x 与城市 y 有直接道路相连。城市由1~N进行编号。接下来的一行,包含一个长度为 N,仅包含小写字母的字符串,第 i 位的字符表示在城市 i 流行的原料类型。 最后一行, 包含一个长度为 M, 仅包含小写字母的字符串, 表示特征字符串。

Output

仅包含一个整数,为 N2 * Expectation

Sample Input

3 5
1 2
1 3
aab
abaab  

Sample Output

15 

Solution

点分治+后缀自动机....

思路是真的神奇...看了好久题解才看明白。

先考虑暴力,有一个很显然的\(O(n^2)\)的暴力:

  • 枚举每个点作为起点,\(dfs\)另一个点,\(dfs\)的同时在特征字符串\(S\)的\(SAM\)上跑,顺便统计答案就好了。
  • 这个在\(SAM\)上跑实际上就相当于每次在一个已经匹配了的串后面加一个字符,那么直接沿着\(SAM\)的转换边走就好了。

换个角度思考,还有另一种暴力:

  • 枚举一个点\(x\),统计出每条以这个点为\(lca\)的路径的代价。
  • 考虑这个看起来高级一点的暴力怎么做,
  • 对于点\(x\),路径肯定是\(a\to x \to b\)的形式,那么我们把他拆成两段\(a\to x\)和\(x \to b\),注意到如果我们把特征字符串反过来,那么这两种其实就是一样的,所以我们现在考虑\(a \to x\)怎么统计,然后在翻转过的\(S\)上再做一遍就好了。
  • 那么我们就是要统计出对于自动机上的点\(i\),有多少以\(x\)结尾的路径字符串在这个点。
  • 那么问题就相当于当前已经匹配了一个串,要在这个串前面加一个字符,那么沿着\(parent\)树跳就好了。
  • 最后答案就是对于字符串上每个点,这个点开始和这个点结束的方案之积 的和。

注意到第二种暴力可以用点分治优化,那么第二种暴力的复杂度就是\(O(n\log n+nm)\)。

考虑如何把后面一项优化一下,注意到第一种方案是不需要每次都扫一遍自动机的,所以可以在点分治的时候设一个阀值\(B\),若\(size>B\)就用第二种,否则用第一种。

可以发现当\(B=\sqrt{n}\)的时候复杂度最优,此时时间复杂度为\(O((n+m)\sqrt{n})\)。

#include<bits/stdc++.h>
using namespace std;#define ll long long void read(int &x) {x=0;int f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}void print(ll x) {if(x<0) putchar('-'),x=-x;if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(ll x) {if(!x) putchar('0');else print(x);putchar('\n');}const int maxn = 2e5+10;
const int inf = 1e9;ll ans;
char s[maxn];
int n,m,rt,siz,B,top;
int head[maxn],tot,a[maxn];
int vis[maxn],f[maxn],sz[maxn],tmp[maxn],t[maxn];
struct edge{int to,nxt;}e[maxn<<1];void ins(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}struct Suffix_Automaton {int cnt,qs,lstp;int par[maxn],tr[maxn][26],ml[maxn],pos[maxn],sz[maxn];int t[maxn],r[maxn],son[maxn][26],str[maxn],tag[maxn],rev[maxn];void append(int x,int v) {int p=lstp,np=++cnt;pos[np]=v,sz[np]=1,ml[np]=ml[p]+1,rev[v]=np;lstp=np;for(;p&&tr[p][x]==0;p=par[p]) tr[p][x]=np;if(!p) return par[np]=qs,void();int q=tr[p][x];if(ml[p]+1<ml[q]) {int nq=++cnt;ml[nq]=ml[p]+1;memcpy(tr[nq],tr[q],sizeof tr[nq]);par[nq]=par[q],par[q]=par[np]=nq;for(;p&&tr[p][x]==q;p=par[p]) tr[p][x]=nq;} else par[np]=q;}void prepare(char *ss) {lstp=qs=cnt=1;for(int i=1;i<=m;i++) append(str[i]=ss[i]-'a',i);for(int i=1;i<=cnt;i++) t[ml[i]]++;for(int i=1;i<=m;i++) t[i]+=t[i-1];for(int i=1;i<=cnt;i++) r[t[ml[i]]--]=i;for(int i=cnt;i;i--) {int p=r[i];sz[par[p]]+=sz[p];if(!pos[par[p]]) pos[par[p]]=pos[p];son[par[p]][str[pos[p]-ml[par[p]]]]=p;}}void mark(int x,int fa,int now,int len) {if(len==ml[now]) now=son[now][a[x]];else if(str[pos[now]-len]!=a[x]) now=0;if(!now) return ;len++;tag[now]++;for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa&&!vis[e[i].to]) mark(e[i].to,x,now,len);}void push() {for(int i=1;i<=cnt;i++) tag[r[i]]+=tag[par[r[i]]];}
}sam1,sam2;void get_rt(int x,int fa) {sz[x]=1,f[x]=0;for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa&&!vis[e[i].to]) get_rt(e[i].to,x),sz[x]+=sz[e[i].to],f[x]=max(f[x],sz[e[i].to]);f[x]=max(f[x],siz-sz[x]);if(f[x]<f[rt]) rt=x;
}void get_node(int x,int fa) {t[++top]=x;for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa&&!vis[e[i].to]) get_node(e[i].to,x);
}void dfs(int x,int fa,int now) {now=sam1.tr[now][a[x]];if(!now) return ;ans+=sam1.sz[now];for(int i=head[x];i;i=e[i].nxt)if(e[i].to!=fa&&!vis[e[i].to]) dfs(e[i].to,x,now);
}void work(int x,int fa,int op) {memset(sam1.tag,0,(sam1.cnt+2)*4);memset(sam2.tag,0,(sam2.cnt+2)*4);if(fa) sam1.mark(x,fa,sam1.tr[1][a[fa]],1),sam2.mark(x,fa,sam2.tr[1][a[fa]],1);else sam1.mark(x,fa,1,0),sam2.mark(x,fa,1,0);sam1.push(),sam2.push();for(int i=1;i<=m;i++) ans+=1ll*op*sam1.tag[sam1.rev[i]]*sam2.tag[sam2.rev[m-i+1]];
}void solve(int x) {get_rt(x,0);siz=sz[x];if(siz<=B) {top=0,get_node(x,0);for(int i=1;i<=top;i++) dfs(t[i],0,sam1.qs);for(int i=1;i<=top;i++) vis[t[i]]=0;return ;}for(int i=head[x];i;i=e[i].nxt) tmp[e[i].to]=sz[e[i].to];work(x,0,1);for(int i=head[x];i;i=e[i].nxt) if(!vis[e[i].to]) work(e[i].to,x,-1);vis[x]=1;for(int i=head[x];i;i=e[i].nxt)if(!vis[e[i].to]) siz=tmp[e[i].to],rt=0,get_rt(e[i].to,x),solve(rt);
}int main() {read(n),read(m);B=sqrt(n);for(int i=1,x,y;i<n;i++) read(x),read(y),ins(x,y),ins(y,x);scanf("%s",s+1);for(int i=1;i<=n;i++) a[i]=s[i]-'a';scanf("%s",s+1);sam1.prepare(s);reverse(s+1,s+m+1);sam2.prepare(s);siz=n,f[0]=inf,get_rt(1,0),solve(rt);write(ans);return 0;
}

转载于:https://www.cnblogs.com/hbyer/p/10456260.html

[BZOJ1921] [CTSC2010]珠宝商相关推荐

  1. bzoj1921: [Ctsc2010]珠宝商

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

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

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

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

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

  4. bzoj 1921: [Ctsc2010]珠宝商

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

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

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

  6. P4218 [CTSC2010]珠宝商

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

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

    [CTSC2010]珠宝商 不错的题目 看似无法做,n<=5e4,8s,根号算法? 暴力一: n^2,+SAM上找匹配点的right集合sz,失配了直接退出 暴力二: O(m) 统计过lca=x ...

  8. bzoj1921 CTSC2010 jewelry

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

  9. [CTSC2010]珠宝商

    题目描述 题解 首先我们考虑一种做法,对于一棵树考虑枚举每个点为根去 dfs\text{dfs}dfs ,然后建立出特征串的 SAM\text{SAM}SAM ,每次走到的点计算 right\text ...

最新文章

  1. python vars 的用法
  2. asp.net mvc 重定向
  3. android绘制河流双曲线,项目三:河道测量试题库(13页)-原创力文档
  4. win10+计算机安全配置,做好个人电脑安全隐私设置Windows10系统磁盘数据加密操作...
  5. caffe 提取特征并可视化(已测试可执行)及在线可视化
  6. 女朋友来大姨妈怎么办?
  7. mysql-查看表-修改表-删除表
  8. Javascript——DOM编程
  9. 【开发工具】之source insight 4常用设置
  10. 开发Google Material Design风格的WPF程序
  11. 为RecyclerView打造通用Adapter
  12. 【数据艺术科技1】基于pyhon的高维数据可视化。(1、2维)
  13. npm 安装yarn
  14. 建行u盾弹不出来_Win7系统检测不到建行网银U盾无法识别的解决方法
  15. Javascript 版万年历
  16. 我是这样手写 Spring 的(麻雀虽小五脏俱全)
  17. Linux基础PHP网站搭建
  18. 虽然不能去故宫办婚礼,但你可以帮故宫找“中纹”啊!
  19. 瑞星发布中国用户最常用十大密码:abc123
  20. java项目实体类方法找不到_报错,居然找不到实体类

热门文章

  1. 流量焦虑意外带来契机,“福禄控股们”赚钱容易做大难?
  2. app常见的 闪退及闪退的原因
  3. 台式计算机默认关机变注销,win10系统关机变注销的解决方案
  4. android 紫外线传感器,Arduino光线传感器-UV Sensor V1.0-ML8511紫外线传感器
  5. android 方法映射,高通Android平台驱动层 MSM8916 键值映射方法
  6. 查找计算机里包含相关文字,搜索word包含文字内容
  7. 还不到4折:赶紧来抢券啊!!!
  8. 冰河在大学是如何度过的?
  9. 数据结构--AVL树(全)
  10. VisionPro软件介绍