BZOJ3946 : 无聊的游戏
首先把所有串拼起来,后插入的串在前面,得到一个大串。
那么任意时刻,每个串是由这个大串的若干个不相交的子串从左到右拼接而成。
用线段树维护每个串,每个节点维护一个标记,表示区间内的串要加上什么前缀。
用可持久化线段树维护这些串和标记,那么合并就是线段树的合并,因为取值区间互不相交,所以每次合并的复杂度为$O(\log L)$。
这样就可以在$O(m\log n\log L)$的时间内支持区间加操作。
然后考虑如何计算区间LCP,设$height_i=LCP(s_i,s_{i+1})$,那么询问$[L,R]$就是询问$\min(height_L,height_{L+1},...,height_{R-1})$。
用线段树维护$height$,每当区间加的时候,对$height$的修改就是区间加上一个定值,然后两端点暴力重新计算LCP。
计算两个串的LCP可以考虑维护Hash值,然后二分答案,单次查询的复杂度为$O(\log^2L)$。
时间复杂度$O(m(\log n+\log L)\log L)$。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned int U;
const int N=50010,M=600010,MAXN=131100;
int n,m,i,j,x,len,cur,st[N],en[N],q[N][3],stq[N],enq[N];U po[M];
char op[9],s[M],pool[M],str[M];
int pre[MAXN],T[N],h[MAXN],tag[MAXN];
namespace DS{
const int MAXM=15000000;
int tot,l[MAXM],r[MAXM],v[MAXM];U f[MAXM];
inline 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]=1;
f[x]=str[a];
return x;
}
int mid=(a+b)>>1;
if(c<=mid)l[x]=build(a,mid,c,d);
if(d>mid)r[x]=build(mid+1,b,c,d);
return up(x),x;
}
int merge(int x,int y,int a,int b){
if(!x||!y)return x+y;
int z=++tot,mid=(a+b)>>1;
l[z]=merge(l[x],l[y],a,mid);
r[z]=merge(r[x],r[y],mid+1,b);
return up(z),z;
}
inline U hash(int x,int k){
int a=1,b=cur,mid,t;U h=0;
while(a<b){
mid=(a+b)>>1,t=v[l[x]];
if(k<=t)b=mid,x=l[x];else h=h*po[t]+f[l[x]],k-=t,a=mid+1,x=r[x];
}
return h*po[v[x]]+f[x];
}
}
inline void ins(int x,int p){pre[x]=DS::merge(pre[x],p,1,cur);}
inline void down(int x){if(pre[x])ins(x<<1,pre[x]),ins(x<<1|1,pre[x]),pre[x]=0;}
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)>>1;
if(c<=mid)push(x<<1,a,mid,c,d,p);
if(d>mid)push(x<<1|1,mid+1,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],1,cur);
pre[x]=0;
return;
}
down(x);
int mid=(a+b)>>1;
if(c<=mid)root(x<<1,a,mid,c);else root(x<<1|1,mid+1,b,c);
}
inline int lcp(int x,int y){
root(1,1,n,x),root(1,1,n,y);
x=T[x],y=T[y];
int l=1,r=min(DS::v[x],DS::v[y]),mid,t=0;
while(l<=r){
mid=(l+r)>>1;
if(DS::hash(x,mid)==DS::hash(y,mid))l=(t=mid)+1;else r=mid-1;
}
return t;
}
inline void tag1(int x,int p){h[x]+=p;tag[x]+=p;}
inline void pb(int x){if(tag[x])tag1(x<<1,tag[x]),tag1(x<<1|1,tag[x]),tag[x]=0;}
inline void up(int x){h[x]=min(h[x<<1],h[x<<1|1]);}
void build(int x,int a,int b){
if(a==b){h[x]=lcp(a,a+1);return;}
int mid=(a+b)>>1;
build(x<<1,a,mid),build(x<<1|1,mid+1,b);
up(x);
}
void cal(int x,int a,int b,int c){
if(a==b){h[x]=lcp(a,a+1);return;}
pb(x);
int mid=(a+b)>>1;
if(c<=mid)cal(x<<1,a,mid,c);else cal(x<<1|1,mid+1,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)>>1;
if(c<=mid)change(x<<1,a,mid,c,d,p);
if(d>mid)change(x<<1|1,mid+1,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)>>1,t=M;
if(c<=mid)t=ask(x<<1,a,mid,c,d);
if(d>mid)t=min(t,ask(x<<1|1,mid+1,b,c,d));
return t;
}
inline void makepush(int l,int r,int A,int B){
push(1,1,n,l,r,DS::build(1,cur,A,B));
if(l<r)change(1,1,n-1,l,r-1,B-A+1);
if(l>1)cal(1,1,n-1,l-1);
if(r<n)cal(1,1,n-1,r);
}
inline int query(int l,int r){
if(l==r)return lcp(l,l);
return ask(1,1,n-1,l,r-1);
}
int main(){
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%s",s);
len=strlen(s);
st[i]=cur+1;
for(j=0;j<len;j++)pool[++cur]=s[j];
en[i]=cur;
}
for(i=1;i<=m;i++){
scanf("%s%d%d",op,&q[i][1],&q[i][2]);
if(op[0]=='Q')q[i][0]=1;
else{
scanf("%s",s);
len=strlen(s);
stq[i]=cur+1;
for(j=0;j<len;j++)pool[++cur]=s[j];
enq[i]=cur;
}
}
for(cur=0,i=m;i;i--)if(!q[i][0]){
x=cur+1;
for(j=stq[i];j<=enq[i];j++)str[++cur]=pool[j];
stq[i]=x,enq[i]=cur;
}
for(i=1;i<=n;i++){
x=cur+1;
for(j=st[i];j<=en[i];j++)str[++cur]=pool[j];
st[i]=x,en[i]=cur;
}
for(po[0]=i=1;i<=cur;i++)po[i]=po[i-1]*233;
for(i=1;i<=n;i++)T[i]=DS::build(1,cur,st[i],en[i]);
build(1,1,n-1);
for(i=1;i<=m;i++)if(q[i][0])printf("%d\n",query(q[i][1],q[i][2]));
else makepush(q[i][1],q[i][2],stq[i],enq[i]);
return 0;
}
BZOJ3946 : 无聊的游戏的更多相关文章
- A - 无聊的游戏 HDU - 1525(博弈)
A - 无聊的游戏 HDU - 1525 疫情当下,有两个很无聊的人,小A和小B,准备玩一个游戏,玩法是这样的,从两个自然数开始比赛.第一个玩家小A从两个数字中的较大者减去两个数字中较小者的任何正倍数 ...
- 几年前无聊小游戏之作_WEB版本打泡泡
几年前写的小东西 主要是H5画布的操作,还有个C语言基于WIN SDK开发的版本 找不到代码了 找到了再分享 <!DOCTYPE html> <script src="ga ...
- [学习笔记]可持久化数据结构——数组、并查集、平衡树、Trie树
可持久化:支持查询历史版本和在历史版本上修改 可持久化数组 主席树做即可. [模板]可持久化数组(可持久化线段树/平衡树) 可持久化并查集 可持久化并查集 主席树做即可. 要按秩合并.(路径压缩每次建 ...
- js小游戏---智力游戏
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD ...
- 暑假热身 E. 无聊的LSY
LSY大牛没事就爱玩游戏,包括很多很无聊的游戏.某日,LSY大牛又找到了一个无聊的游戏:每一局游戏的开始,LSY大牛将代表自己的棋子放在一个线性棋盘的最左端(第0个格子,可以认为向右端无限延伸),接着 ...
- bzoj4702: 装箱游戏
Description Alice和Bob正在玩一个非常无聊的游戏以打发时间.游戏是这样的.初始的时候,有n个箱子和m个物品.箱子.物 品都是不同的.因此有nm种方法把这些物品放到箱子里.两个人轮流操 ...
- win10 uwp 商业游戏 1.2.1
上一个游戏已经告诉大家如何写多个游戏,现在继续写这个无聊的游戏 希望大家在看这篇文章之前先看win10 uwp 商业游戏,在这个文章告诉了大家如何创建游戏. 修改数值 可以从上一篇的博客的游戏看到升级 ...
- win10 uwp 商业游戏 1.1.5
本文是在win10 uwp 商业游戏 基础上继续开发,添加一些无聊的游戏 因为在发布几个月,下载量很少,小伙伴说游戏就玩不到几分钟就不想玩,于是我就想加入其他游戏 下面我来告诉大家如何在游戏中添加多个 ...
- 2018-8-10-win10-uwp-商业游戏-1.2.1
title author date CreateTime categories win10 uwp 商业游戏 1.2.1 lindexi 2018-08-10 19:16:50 +0800 2018- ...
随机推荐
- XMPP框架下微信项目总结(4)重新连接服务器
xmpp 很多功能是面向模块开发的 例如电子名片 无须自己去写请求的代码XMPP(文件)->Extension(存放的是各个模块)->Reconnect(自动连接模块) ...
- hud 2602 Bone Collector
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2602 思路:典型的01背包 #include<stdlib.h> #include< ...
- JavaScript基础——数据类型
JavaScript使用数据类型来确定如何处理被分配给一个变量的数据.变量的类型决定了你可以对变量进行什么操作,如循环或者执行.下面描述了最常用的变量类型. 字符串(String):此数据类型将字符数 ...
- C#的面向对象特性之多态
using System; using System.Collections; using System.Collections.Generic; namespace codeTest { class ...
- 菜鸟学Linux命令:端口查看和操作命令
>>端口和进程 端口不是独立存在的,它是依附于进程的.某个进程开启,那么它对应的端口就开启了,进程关闭,则该端口也就关闭了.下次若某个进程再次开启,则相应的端口也再次开启. >> ...
- Eclipse 快捷键 转换为Netbeans 快捷键
一直使用netbeans IDE开发,习惯了netbeans的快捷键,最近要开发个app就选择了H5. 接着使用了HBuilder (基于Eclipse开发) 总体来讲这个IDE还可以,不管是代码提示 ...
- Task使用小结
Task是.NET推出数据任务处理的工作类,Task的使用也被越来越多的人讲解,这里仅仅介绍Task的部分使用介绍: 1.Task简单创建 --无返回值 Task.Factory.StartNew(( ...
- Log4Net配置以及使用
跟踪程序代码,及时发现程序的运行状态,是每个成熟的软件所必不可少的一个环节,网站发布到真实的环境之后,对于程序的运行状态,我们并不能想开发环境那也,点击调试.日志记录显示就尤为重要,在.NET中记录日 ...
- 类模板Queue的实现
#include <iostream> #include <vector> using namespace std; template <class Type> c ...
- Action处理请求参数
第一种 :Action 本身作为model对象,通过成员setter封装 (属性驱动 ) 第一种方式:<br> <form action="${pageContext.re ...