bzoj3946
题解:
树套树
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的更多相关文章
- BZOJ3946 : 无聊的游戏
首先把所有串拼起来,后插入的串在前面,得到一个大串. 那么任意时刻,每个串是由这个大串的若干个不相交的子串从左到右拼接而成. 用线段树维护每个串,每个节点维护一个标记,表示区间内的串要加上什么前缀. ...
- [学习笔记]可持久化数据结构——数组、并查集、平衡树、Trie树
可持久化:支持查询历史版本和在历史版本上修改 可持久化数组 主席树做即可. [模板]可持久化数组(可持久化线段树/平衡树) 可持久化并查集 可持久化并查集 主席树做即可. 要按秩合并.(路径压缩每次建 ...
随机推荐
- 网站精准查询IP
分享一些网站能精准查询IP的 https://www.chaidu.com/App/Web/IP/ http://www.ipip.net/ip.html http://www.hao7188.com ...
- Python3基础 list 使用for循环 删除列表中的重复项
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- Python3基础 sys.path.append 增加模块的搜索路径
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- label表单的关联性
<input type="checkbox" id="cr" /> <label for="cr">点击关联复选框& ...
- Ansible 操作windows
1.主控端安装ansible 1) pip install ansible 2.主控端安装相关的包 pip install http://github.com/diyan/pywi ...
- BZOJ 2648 kd-tree模板
学习了一下kd-tree的基本写法 http://blog.csdn.net/jiangshibiao/article/details/34144829 配合 http://www.bilibili. ...
- 正则表达式及R字符串处理之终结版
http://yphuang.github.io/blog/2016/03/15/regular-expression-and-strings-processing-in-R/ 0.动机:为什么学习字 ...
- 小米笔记本 air 12.5寸 支持硬盘参数
M.2接口 2280规格 单面芯片固态硬盘 PCIE协议
- 编写 R Markdown 文档
数据分析师的工作不仅是将数据放入模型并得出一些结论.通常需要完成从数据收集.数据清理.可视化.建模再到最后编写报告或制作演示文稿的完整工作流程.在前面几章中,我们从不同方面深入学习 R 编程语言,从各 ...
- 字符集(编码)转换_Qt532_QString
1.网上的资料: 1.1.参考网址:http://blog.csdn.net/changsheng230/article/details/6588447 1.2.网页内容: “ Qt 使用Unicod ...