题解:

树套树

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. git_如何查看两个版本之间那些文件被修改

    需求 由于工程比较庞大,接近500M,每部署一次如果都全量部署,不仅仅磁盘空间耗费较大,最主要是要等很长时间, 之前就一直有这个问题,但是也就没有弄,上周领导发话了,这个问题必须要解决了 前记 增加带 ...

  2. 如何修改ls命令列出来的目录颜色

    答:默认为蓝色,在黑色背景下无法看清楚,因此以以下方法修改; 1.往~/.bash_profile文件中添加以下内容: export LS_COLORS='no=00:fi=00:di=01;33:l ...

  3. 最全的Spring面试题和答案<一>

    1.什么是Spring框架?Spring框架有哪些主要模块? Spring框架是一个为Java应用程序的开发提供了综合.广泛的基础性支持的Java平台.Spring帮助开发者解决了开发中基础性的问题, ...

  4. 【修改帐号信息】Eclipse中修改SVN用户名和密码方法

    由于在svn 的界面中并没有为我们提供直接更换用户名密码的地方,所以一旦我们需要更换用户名的就需要自己想一些办法. 解决方案: 在Eclipse 使用SVN 的过程中大多数人往往习惯把访问SVN 的用 ...

  5. Luogu 2671 求和 NOIP2015T3

    题目链接 题解 20pts $O(n^3)$枚举$x,y,z$,根据题目要求判断 40pts $O(n^2)$枚举$x,z$,需要满足$x,z$奇偶相同 20~40pts的代码我都没有写过...就不贴 ...

  6. [BZOJ4027][HEOI2015]兔子与樱花 树形dp

    Description 很久很久之前,森林里住着一群兔子.有一天,兔子们突然决定要去看樱花.兔子们所在森林里的樱花树很特殊.樱花树由n个树枝分叉点组成,编号从0到n-1,这n个分叉点由n-1个树枝连接 ...

  7. UVa 10817 校长的烦恼

    https://vjudge.net/problem/UVA-10817 题意: 某校有m个教师和n个求职者,需讲授s个课程,已知每人的工资c和能教的课程集合,要求支付最少的工资使得每门课都至少有两名 ...

  8. UVa 437 巴比伦塔

    https://vjudge.net/problem/UVA-437 这道题和HDU的Monkey and Banana完全一样. #include<iostream> #include& ...

  9. BZOJ 4571 【SCOI2016】 美味

    题目链接:美味 如果题目里面没有那个\(a_i\),这道题就可以直接在\(Trie\)树上走一走就做完了.现在多了个\(a_i\),\(Trie\)树就无能为力了. 我们考虑一下在\(Trie\)树上 ...

  10. Linq 常用方法解释

    /// <summary> /// linq /// </summary> public class Linq { /// <summary> /// 测试 /// ...