题意:有一棵树,树上每个结点上有一个字母,有两种操作:

1)询问树上两点u,v间有向路径上有多少个字母和某个固定的字符串相匹配

2)将结点u的字母修改为x

树剖+线段,暴力维护前缀和后缀哈希值(正反都要维护)以及区间内匹配的个数,合并两区间时判断一下跨过分界点的情况就行了。由于被匹配的字符串长度不超过100,所以最多只需维护长度为100的前缀/后缀。

但即使这样复杂度也足足有$O(100nlog^2n)$啊,这常数是得有多小才能过掉...

注意各种条件判断和细节处理,还有就是这题内存比较吃紧,使用动态开点可以节省一半的内存。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef unsigned long long ll;
  4. const int N=1e5+,M=;
  5. int hd[N],n,ne,m,Len,fa[N],son[N],siz[N],dep[N],top[N],dfn[N],rnk[N],tot,rt,ls[N<<],rs[N<<],tot2;
  6. ll H,pm[N];
  7. char s1[N],s2[N];
  8. struct D {
  9. int len,sum;
  10. ll L[],R[];
  11. D(int ch=) {
  12. len=;
  13. sum=(Len==&&ch==H);
  14. L[]=R[]=ch;
  15. }
  16. } tr[N<<][];
  17. struct E {int v,nxt;} e[N<<];
  18. D operator+(const D& a,const D& b) {
  19. if(a.L[]==)return b;
  20. if(b.L[]==)return a;
  21. D c;
  22. c.len=a.len+b.len;
  23. c.sum=a.sum+b.sum;
  24. for(int i=; i<=min(,c.len); ++i) {
  25. if(i<=a.len)c.L[i]=a.L[i];
  26. else c.L[i]=a.L[a.len]*pm[i-a.len]+b.L[i-a.len];
  27. if(i<=b.len)c.R[i]=b.R[i];
  28. else c.R[i]=a.R[i-b.len]*pm[b.len]+b.R[b.len];
  29. }
  30. for(int i=max(,Len-b.len); i<=a.len&&i<=Len-; ++i)if(a.R[i]*pm[Len-i]+b.L[Len-i]==H)c.sum++;
  31. return c;
  32. }
  33. void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;}
  34. void dfs1(int u,int f,int d) {
  35. fa[u]=f,son[u]=,siz[u]=,dep[u]=d;
  36. for(int i=hd[u]; ~i; i=e[i].nxt) {
  37. int v=e[i].v;
  38. if(v==fa[u])continue;
  39. dfs1(v,u,d+),siz[u]+=siz[v];
  40. if(siz[v]>siz[son[u]])son[u]=v;
  41. }
  42. }
  43. void dfs2(int u,int tp) {
  44. top[u]=tp,dfn[u]=++tot,rnk[dfn[u]]=u;
  45. if(son[u])dfs2(son[u],top[u]);
  46. for(int i=hd[u]; ~i; i=e[i].nxt) {
  47. int v=e[i].v;
  48. if(v==fa[u]||v==son[u])continue;
  49. dfs2(v,v);
  50. }
  51. }
  52. #define mid ((l+r)>>1)
  53. void pu(int u) {
  54. tr[u][]=tr[ls[u]][]+tr[rs[u]][];
  55. tr[u][]=tr[rs[u]][]+tr[ls[u]][];
  56. }
  57. void upd(int p,int x,int& u=rt,int l=,int r=tot) {
  58. if(l==r) {tr[u][]=tr[u][]=D(x); return;}
  59. p<=mid?upd(p,x,ls[u],l,mid):upd(p,x,rs[u],mid+,r);
  60. pu(u);
  61. }
  62. void build(int& u=rt,int l=,int r=tot) {
  63. u=++tot2;
  64. if(l==r) {tr[u][]=tr[u][]=D(s2[rnk[l]-]); return;}
  65. build(ls[u],l,mid),build(rs[u],mid+,r),pu(u);
  66. }
  67. D qry(int L,int R,int f,int u=rt,int l=,int r=tot) {
  68. if(l>=L&&r<=R)return tr[u][f];
  69. if(l>R||r<L)return D();
  70. if(f==)return qry(L,R,f,ls[u],l,mid)+qry(L,R,f,rs[u],mid+,r);
  71. else return qry(L,R,f,rs[u],mid+,r)+qry(L,R,f,ls[u],l,mid);
  72. }
  73. int qry2(int u,int v) {
  74. D L=D(),R=D(),M;
  75. for(; top[u]!=top[v];) {
  76. if(dep[top[u]]>dep[top[v]])L=L+qry(dfn[top[u]],dfn[u],),u=fa[top[u]];
  77. else R=qry(dfn[top[v]],dfn[v],)+R,v=fa[top[v]];
  78. }
  79. if(dep[u]>dep[v])M=qry(dfn[v],dfn[u],);
  80. else M=qry(dfn[u],dfn[v],);
  81. return (L+M+R).sum;
  82. }
  83. int main() {
  84. pm[]=;
  85. for(int i=; i<N; ++i)pm[i]=pm[i-]*M;
  86. memset(hd,-,sizeof hd),ne=;
  87. scanf("%d%d",&n,&m);
  88. scanf("%s%s",s1,s2),Len=strlen(s1);
  89. H=;
  90. for(int i=; i<Len; ++i)H=H*M+s1[i];
  91. for(int i=; i<n; ++i) {
  92. int u,v;
  93. scanf("%d%d",&u,&v);
  94. addedge(u,v);
  95. addedge(v,u);
  96. }
  97. dfs1(,,),dfs2(,);
  98. build(rt);
  99. while(m--) {
  100. int f,u,v;
  101. char ch;
  102. scanf("%d",&f);
  103. if(f==)scanf("%d%d",&u,&v),printf("%d\n",qry2(u,v));
  104. else scanf("%d %c",&u,&ch),upd(dfn[u],ch);
  105. }
  106. return ;
  107. }

当然还有$O(100nlogn)$的LCT毒瘤做法,代码比树剖短,需要特判的地方少,而且更省内存,但是常数巨大,需要优化下常数才能过,比如改个引用传递什么的。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef unsigned long long ll;
  4. const int N=1e5+,M=;
  5. int n,m,a[N],fa[N],ch[N][],flp[N],sta[N],tp,Len;
  6. ll H,pm[N];
  7. char s1[N],s2[N];
  8. struct D {
  9. int len,sum;
  10. ll L[],R[];
  11. D(int ch=) {
  12. len=;
  13. sum=(Len==&&ch==H);
  14. L[]=R[]=ch;
  15. }
  16. } tr[N][];
  17. D operator+(const D& a,const D& b) {
  18. if(a.L[]==)return b;
  19. if(b.L[]==)return a;
  20. D c;
  21. c.len=a.len+b.len;
  22. c.sum=a.sum+b.sum;
  23. for(int i=; i<=min(,c.len); ++i) {
  24. if(i<=a.len)c.L[i]=a.L[i];
  25. else c.L[i]=a.L[a.len]*pm[i-a.len]+b.L[i-a.len];
  26. if(i<=b.len)c.R[i]=b.R[i];
  27. else c.R[i]=a.R[i-b.len]*pm[b.len]+b.R[b.len];
  28. }
  29. for(int i=max(,Len-b.len); i<=a.len&&i<=Len-; ++i)if(a.R[i]*pm[Len-i]+b.L[Len-i]==H)c.sum++;
  30. return c;
  31. }
  32. #define l(u) ch[u][0]
  33. #define r(u) ch[u][1]
  34. void rev(int u) {flp[u]^=,swap(l(u),r(u)),swap(tr[u][],tr[u][]);}
  35. void pu(int u) {
  36. tr[u][]=tr[l(u)][]+D(s2[u])+tr[r(u)][];
  37. tr[u][]=tr[r(u)][]+D(s2[u])+tr[l(u)][];
  38. }
  39. void pd(int u) {if(flp[u])rev(l(u)),rev(r(u)),flp[u]=;}
  40. int sf(int u) {return u==r(fa[u]);}
  41. bool isrt(int u) {return u!=l(fa[u])&&u!=r(fa[u]);}
  42. void rot(int u) {
  43. int v=fa[u],f=sf(u);
  44. if(!isrt(v))ch[fa[v]][sf(v)]=u;
  45. ch[v][f]=ch[u][f^],fa[ch[v][f]]=v;
  46. fa[u]=fa[v],ch[u][f^]=v,fa[v]=u,pu(v);
  47. }
  48. void splay(int u) {
  49. sta[tp=]=u;
  50. for(int v=u; !isrt(v); v=fa[v])sta[++tp]=fa[v];
  51. for(; ~tp; pd(sta[tp--]));
  52. for(; !isrt(u); rot(u))if(!isrt(fa[u])&&sf(fa[u])==sf(u))rot(fa[u]);
  53. pu(u);
  54. }
  55. void access(int u) {for(int v=; u; splay(u),r(u)=v,pu(u),u=fa[v=u]);}
  56. void makert(int u) {access(u),splay(u),rev(u);}
  57. void link(int u,int v) {makert(u),fa[u]=v;}
  58. void join(int u,int v) {makert(u),access(v),splay(v);}
  59. void upd(int u,int ch) {splay(u),s2[u]=ch;}
  60. int qry(int u,int v) {join(u,v); return tr[v][].sum;}
  61. int main() {
  62. pm[]=;
  63. for(int i=; i<N; ++i)pm[i]=pm[i-]*M;
  64. scanf("%d%d",&n,&m);
  65. scanf("%s%s",s1,s2+),Len=strlen(s1);
  66. H=;
  67. for(int i=; i<Len; ++i)H=H*M+s1[i];
  68. for(int i=; i<n; ++i) {
  69. int u,v;
  70. scanf("%d%d",&u,&v);
  71. link(u,v);
  72. }
  73. while(m--) {
  74. int f,u,v;
  75. char ch;
  76. scanf("%d",&f);
  77. if(f==)scanf("%d%d",&u,&v),printf("%d\n",qry(u,v));
  78. else scanf("%d %c",&u,&ch),upd(u,ch);
  79. }
  80. return ;
  81. }

Gym - 101908H Police Hypothesis (树链剖分/LCT+字符串哈希)的更多相关文章

  1. Bzoj 2243: [SDOI2011]染色 树链剖分,LCT,动态树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5020  Solved: 1872[Submit][Status ...

  2. Bzoj 1036: [ZJOI2008]树的统计Count 树链剖分,LCT

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 11102  Solved: 4490[Submit ...

  3. [CodeVS2370] 小机房的树 (LCA, 树链剖分, LCT)

    Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花 ...

  4. 【bzoj4811】[Ynoi2017]由乃的OJ 树链剖分/LCT+贪心

    Description 给你一个有n个点的树,每个点的包括一个位运算opt和一个权值x,位运算有&,l,^三种,分别用1,2,3表示. 每次询问包含三个数x,y,z,初始选定一个数v.然后v依 ...

  5. BZOJ2243: [SDOI2011]染色(树链剖分/LCT)

    Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如 ...

  6. bzoj 4817: [Sdoi2017]树点涂色【树链剖分+LCT】

    非常妙的一道题. 首先对于操作一"把点x到根节点的路径上所有的点染上一种没有用过的新颜色",长得是不是有点像LCT中的access操作?进而发现,如果把同一颜色的点连起来作为LCT ...

  7. [BZOJ2157]旅游(树链剖分/LCT)

    树剖裸题,当然LCT也可以. 树剖: #include<cstdio> #include<algorithm> #define ls (x<<1) #define ...

  8. Gym - 102040F Path Intersection (树链剖分+线段树)

    题意:给出棵树上的k条路径,求这些路径的公共点数量. 将每条路径上的点都打上标记,被标记过k次的点就是公共点了.由于公共点形成的区间是连续的,因此直接在线段树上暴搜即可在$O(logn)$求出一条链上 ...

  9. 【BZOJ】1036: [ZJOI2008]树的统计Count(lct/树链剖分)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1036 lct: (ps:为嘛我的那么慢T_T,不知道排到哪了..难道别人都是树剖吗...看来有必要学 ...

随机推荐

  1. ubuntu 设置qt程序开机启动

    1.建立一个桌面文件,forklift-app.desktop Name填写程序的名字 Exec执行程序的路径 [Desktop Entry] Version=1.0 Name=forklift-ap ...

  2. hbase的架构组成+hbase在create报错 -hue - mvn

    0.hbase的组件 架构 参考:https://cloud.tencent.com/developer/article/1084209 各个组件的功能 参考:https://zhuanlan.zhi ...

  3. session到底是何时何地生成的

    关于session,之前只是在用,从没考虑到底怎么生成的 今天有空我做了个实验,把监控了一下访问某网站第一二次的请求响应详细信息,终于搞明白了,好了,开始放图  这里发起一个请求,然后我们看下第一次请 ...

  4. 解决应用程序无法正常启动0xc0150002问题(转)

    简述:使用VS2008写了一个MFC程序,结果传到别人的机子上(WIN7)出现应用程序正常初始化(0xc0150002)失败的问题.为什么我的机子上可以,而别人的机子上运行不了呢?下面是我找到的一个解 ...

  5. Java基础(五)

    方法概述 方法的定义格式 什么是方法?方法就好像是一个工厂. 如奶牛场 原料:奶牛,饲料 产出物:牛奶,各种奶制品 程序当中的方法 参数(原料):进入方法的数据 返回值(产出物):从方法中出来的数据 ...

  6. python并发编程-进程池线程池-协程-I/O模型-04

    目录 进程池线程池的使用***** 进程池/线程池的创建和提交回调 验证复用池子里的线程或进程 异步回调机制 通过闭包给回调函数添加额外参数(扩展) 协程*** 概念回顾(协程这里再理一下) 如何实现 ...

  7. 用css、如何让图片自动适应屏幕大小,不出现滚动条,不变形,兼容各个浏览器?急!!!

    如果是个背景图的话,定义一个div,高100%,宽100%,里面放个img<div class='bg'> <img src="images/bg.jpg" al ...

  8. 01 Linux常用基本命令(一)

    1.远程连接服务器 Xshell为例: ssh 用户名@IP地址 (ssh root@192.168.119.139) 查看服务器的IP地址: ifconfig (ip addr) 2.命令 1.ls ...

  9. react 不同环境配置不同域名

    npm eject 先将配置文件暴露出来 将scripts中的build文件复制一份,改名为你需要的名字 将其中的 process.env.NODE_ENV 赋值为你需要的环境 在package.js ...

  10. 关于catopen函数

    关于catopen函数: 参考网址:http://pubs.opengroup.org/onlinepubs/009695399/functions/catopen.html 1)编辑消息文件 [ro ...