题解:

树套树

treap+线段树

treap就把线段树上的节点弄一下

然后修改的时候

把中间的一段一起加

把两头重新计算(二分+hash)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned int U;
const int N=;
int n,m,x,len,cur,st[N],en[N],q[N][],stq[N];
int pre[N],y[N],h[N],T[N],tag[N],enq[N];
U po[N];
char op[],s[N],pool[N],str[N];
namespace DS
{
const int N=;
int tot,l[N],r[N],v[N];
U f[N];
void up(int x)
{
v[x]=v[l[x]]+v[r[x]];
f[x]=f[l[x]]*po[v[r[x]]]+f[r[x]];
}
int build(int a,int b,int c,int d)
{
int x=++tot;
if (a==b)
{
v[x]=;
f[x]=str[a];
return x;
}
int mid=(a+b)/;
if (c<=mid)l[x]=build(a,mid,c,d);
if (d>mid)r[x]=build(mid+,b,c,d);
up(x);
return x;
}
int merge(int x,int y,int a,int b)
{
if (!x||!y)return x+y;
int z=++tot,mid=(a+b)/;
l[z]=merge(l[x],l[y],a,mid);
r[z]=merge(r[x],r[y],mid+,b);
up(z);
return z;
}
U hash(int x,int k)
{
int a=,b=cur,mid,t;
U h=;
while (a<b)
{
mid=(a+b)/;
t=v[l[x]];
if (k<=t)
{
b=mid;
x=l[x];
}
else
{
h=h*po[t]+f[l[x]];
k-=t;
a=mid+;
x=r[x];
}
}
return h*po[v[x]]+f[x];
}
}
void ins(int x,int p)
{
pre[x]=DS::merge(pre[x],p,,cur);
}
void down(int x)
{
if (pre[x])
{
ins(x<<,pre[x]);
ins(x<<|,pre[x]);
pre[x]=;
}
}
void push(int x,int a,int b,int c,int d,int p)
{
if (c<=a&&b<=d)
{
ins(x,p);
return;
}
down(x);
int mid=(a+b)/;
if (c<=mid)push(x<<,a,mid,c,d,p);
if (d>mid)push(x<<|,mid+,b,c,d,p);
}
void root(int x,int a,int b,int c)
{
if (a==b)
{
T[a]=DS::merge(T[a],pre[x],,cur);
pre[x]=;
return;
}
down(x);
int mid=(a+b)/;
if (c<=mid)root(x<<,a,mid,c);
else root(x<<|,mid+,b,c);
}
int lcp(int x,int y)
{
root(,,n,x);
root(,,n,y);
x=T[x];y=T[y];
int l=,r=min(DS::v[x],DS::v[y]),t=;
while (l<=r)
{
int mid=(l+r)/;
if (DS::hash(x,mid)==DS::hash(y,mid))l=(t=mid)+;
else r=mid-;
}
return t;
}
void tag1(int x,int p)
{
h[x]+=p;
tag[x]+=p;
}
void pb(int x)
{
if (tag[x])
{
tag1(x<<,tag[x]);
tag1(x<<|,tag[x]);
tag[x]=;
}
}
void up(int x)
{
h[x]=min(h[x<<],h[x<<|]);
}
void build(int x,int a,int b)
{
if (a==b)
{
h[x]=lcp(a,a+);
return;
}
int mid=(a+b)/;
build(x<<,a,mid);
build(x<<|,mid+,b);
up(x);
}
void cal(int x,int a,int b,int c)
{
if (a==b)
{
h[x]=lcp(a,a+);
return;
}
pb(x);
int mid=(a+b)/;
if (c<=mid)cal(x<<,a,mid,c);
else cal(x<<|,mid+,b,c);
up(x);
}
void change(int x,int a,int b,int c,int d,int p)
{
if (c<=a&&b<=d)
{
tag1(x,p);
return;
}
pb(x);
int mid=(a+b)/;
if (c<=mid)change(x<<,a,mid,c,d,p);
if (d>mid)change(x<<|,mid+,b,c,d,p);
up(x);
}
int ask(int x,int a,int b,int c,int d)
{
if (c<=a&&b<=d)return h[x];
pb(x);
int mid=(a+b)/,t=N;
if (c<=mid)t=ask(x<<,a,mid,c,d);
if (d>mid)t=min(t,ask(x<<|,mid+,b,c,d));
return t;
}
void makepush(int l,int r,int A,int B)
{
push(,,n,l,r,DS::build(,cur,A,B));
if (l<r)change(,,n-,l,r-,B-A+);
if (l>)cal(,,n-,l-);
if (r<n)cal(,,n-,r);
}
int query(int l,int r)
{
if (l==r)return lcp(l,l);
return ask(,,n-,l,r-);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=;i<=n;i++)
{
scanf("%s",s);
len=strlen(s);
st[i]=cur+;
for (int j=;j<len;j++)pool[++cur]=s[j];
en[i]=cur;
}
for (int i=;i<=m;i++)
{
scanf("%s%d%d",op,&q[i][],&q[i][]);
if (op[]=='Q')q[i][]=;
else
{
scanf("%s",s);
len=strlen(s);
stq[i]=cur+;
for (int j=;j<len;j++)pool[++cur]=s[j];
enq[i]=cur;
}
}
int cur=;
for (int i=m;i;i--)
if (!q[i][])
{
x=cur+;
for (int j=stq[i];j<=enq[i];j++)str[++cur]=pool[j];
stq[i]=x;
enq[i]=cur;
}
for (int i=;i<=n;i++)
{
x=cur+;
for (int j=st[i];j<=en[i];j++)str[++cur]=pool[j];
st[i]=x;en[i]=cur;
}
po[]=;
for (int i=;i<=cur;i++)po[i]=po[i-]*;
for (int i=;i<=n;i++)T[i]=DS::build(,cur,st[i],en[i]);
build(,,n-);
for (int i=;i<=m;i++)
if (q[i][])printf("%d\n",query(q[i][],q[i][]));
else makepush(q[i][],q[i][],stq[i],enq[i]);
}

bzoj3946的更多相关文章

  1. BZOJ3946 : 无聊的游戏

    首先把所有串拼起来,后插入的串在前面,得到一个大串. 那么任意时刻,每个串是由这个大串的若干个不相交的子串从左到右拼接而成. 用线段树维护每个串,每个节点维护一个标记,表示区间内的串要加上什么前缀. ...

  2. [学习笔记]可持久化数据结构——数组、并查集、平衡树、Trie树

    可持久化:支持查询历史版本和在历史版本上修改 可持久化数组 主席树做即可. [模板]可持久化数组(可持久化线段树/平衡树) 可持久化并查集 可持久化并查集 主席树做即可. 要按秩合并.(路径压缩每次建 ...

随机推荐

  1. tomcat部署项目如何去掉项目名称

    去掉项目名和端口: 首先,进入tomcat的安装目录下的conf目录,我的目录是 /usr/local/apache-tomcat-6.0.20/conf,编辑文件server.xml. 1.去除端口 ...

  2. 初始 DQN 程序 所遇到的问题

    初始 DQN 程序 所遇到的问题 最近在看 DQN,但是想试试别人放出来的 code,但是发现,额,各种问题,在此记录,以备不时之需! 问题1. wangxiao@GTX980:~/Documents ...

  3. Hadoop Hive概念学习系列之hive里的分区(九)

    为了对表进行合理的管理以及提高查询效率,Hive可以将表组织成“分区”. 分区是表的部分列的集合,可以为频繁使用的数据建立分区,这样查找分区中的数据时就不需要扫描全表,这对于提高查找效率很有帮助. 分 ...

  4. 关于ArrayList.clear()与=null以及new ArrayList<E>()

    ArrayList是常用到的JCF类,用来保存类型相同的一组对象,并通过下标来快速访问指定对象.今天讨论的是当我们使用完ArrayList后应该选择怎样合适的处理方式. 这里现在有三种方式如下: 1. ...

  5. Java 面向对象之static,final,匿名对象,内部类,包,修饰符

    01final关键字概念 A: 概述 继承的出现提高了代码的复用性,并方便开发.但随之也有问题,有些类在描述完之后,不想被继承, 或者有些类中的部分方法功能是固定的,不想让子类重写.可是当子类继承了这 ...

  6. tmp for cassandra batch delete

    now i have no time to verify this bash script. it is hard for me to delete each data via primary key ...

  7. 探秘AOP实现原理

    可以这么说,AOP是基于动态代理实现的. 那么,这个过程是怎样的? 首先,我们有这样的一个Service类,它是被作为切面的一个类: public class Service implements U ...

  8. 大数据存储的进化史 --从 RAID 到 Hdfs

    我们都知道现在大数据存储用的基本都是 Hdfs ,但在 Hadoop 诞生之前,我们都是如何存储大量数据的呢?这次我们不聊技术架构什么的,而是从技术演化的角度来看看 Hadoop Hdfs. 我们先来 ...

  9. 常用 对象检测 api

    isPrototypeOf()    判断某个 proptotype 对象和某个实例之间的关系 alert(Cat.prototype.isPrototypeOf(cat1)); //true ale ...

  10. 浏览器滚动条及其影响 calc()

    1.浏览器滚动条 默认风格各异,推荐一插件  mCustomScrollbar 不考虑兼容也可自定义样式    链接二 2.影响 以垂直方向为例,当内容变化的时候,如果设置的是overflow:aut ...