题解 无聊的游戏
神仙题,想不到,而且空间卡不过去
首先发现区间加字符串这个操作令人智熄至极
第一思路是离线什么的把这个搞掉
然后看一眼她要查询啥:区间 lcp
完蛋
于是正解:
首先有一个转化:
- 带修区间 lcp 等问题可以考虑维护一个像后缀数组一样的数组记录第 \(i\) 个字符串和第 \(i-1\) 个字符串的 lcp
于是区间 \([l, r]\) 的 lcp 就是 \(\min\limits_{i=l+1}^r\{a_i\}\)
修改区间 \([l, r]\) 之后更新 \(l, r+1\) 的 \(a_i\),然后给区间 \([l+1, r]\) 做区间加即可
貌似是一种高级的差分方法
于是现在区间加字符串的操作暂时没掉了
考虑怎么去更新 \(l, r+1\) 这两个位置
发现同样难以维护
也许离线下来各种乱搞一下能行?(没细想
于是捡回来刚才区间加字符串的操作
考虑线段树每个叶子节点维护一棵平衡树记录这个位置的字符串
区间加不好处理,但如果用可持久化平衡树的话可以转化为区间 merge
发现这个 tag 是支持合并的,于是可以线段树
那在平衡树上顺便维护出hash值,二分答案即可
于是我们现在有了一个时间,空间复杂度均为 \(O(nlog^2n)\) 的做法
然后你就被卡常了
我们发现空间上需要 1.5 个 G,开不下
于是回来优化
首先 tag 常规思路是存字符串的根节点,但我nt了给它单独开了个 rot 数组
然后发现还是卡不过
发现我的思路严重僵化了
因为只有单点查询,所以所有非叶子节点的 val 都是无意义的,直接忽略即可
于是空间就可以勉强卡过了
拿笔记本的键盘写这题写死我了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 18000100
#define N2 50010
#define ll long long
#define ull unsigned int
//#define int long long
int n, m;
int tot;
char s[2][N2], op[N2];
ull pw[600010];
const ull base=13131;
int cnt;
namespace treap{
int rot[N], tot;
struct node{int siz, son[2], rnd; ull val, sum;}tr[N];
#define rot(a) tr[a].rot
#define rnd(a) tr[a].rnd
#define son(a, b) tr[a].son[b]
#define siz(a) tr[a].siz
#define val(a) tr[a].val
#define sum(a) tr[a].sum
inline void pushup(int p) {siz(p)=siz(son(p, 0))+siz(son(p, 1))+1; sum(p)=sum(son(p, 0))+val(p)*pw[siz(son(p, 0))]+sum(son(p, 1))*pw[siz(son(p, 0))+1];}
inline int setup(ull dat) {siz(++tot)=1; sum(tot)=val(tot)=dat; rnd(tot)=rand(); return tot;}
inline int qsiz(int a) {return siz(rot[a]);}
void split(int u, int k, int& x, int& y) {
if (!u) {x=y=0; return ;}
int v=++tot; tr[v]=tr[u];
if (siz(son(u, 0))+1<=k) x=v, split(son(v, 1), k-siz(son(v, 0))-1, son(v, 1), y);
else y=v, split(son(v, 0), k, x, son(v, 0));
pushup(v);
}
ull qsum(int u, int k) {
if (!u) return 0;
if (k>siz(u)) return sum(u);
ull ans=0; int dlt=0, v;
while (1) {
v=son(u, 0);
if (k<=siz(v)) u=v;
else if (k>siz(v)+1) ans+=sum(v)*pw[dlt], dlt+=siz(v), ans+=val(u)*pw[dlt++], u=son(u, 1), k-=siz(v)+1;
else return ans+=sum(v)*pw[dlt], dlt+=siz(v), ans+=val(u)*pw[dlt];
}
}
int merge(int x, int y) {
if (!(x&&y)) return x|y;
int u=++tot;
if (rnd(x)<rnd(y)) tr[u]=tr[x], son(u, 1)=merge(son(u, 1), y);
else tr[u]=tr[y], son(u, 0)=merge(x, son(u, 0));
pushup(u);
return u;
}
void show(int p) {
if (!p) return ;
show(son(p, 0));
printf("%c", char(val(p)));
show(son(p, 1));
}
void upd(int u, char* s) {++cnt; for (int i=1; s[i]; ++i) rot[u]=merge(rot[u], setup(s[i]));}
void upd(int u, int tag) {++cnt; rot[u]=merge(rot[tag], rot[u]);}
ull query(int u, int k) {
if (!k) return 0;
// int x, y, bkp; ull ans;
// assert(siz(rot[u])>=k);
// bkp=tot;
// split(rot[u], k, x, y);
// ans=sum(x);
// while (tot>bkp) tr[tot--]={};
ull ans=qsum(rot[u], k);
return ans;
}
}
namespace seg1{
bool leaf[N2<<2];
int tl[N2<<2], tr[N2<<2], tag[N2<<2], val[N2<<2];
#undef val
#define tl(p) tl[p]
#define tr(p) tr[p]
#define tag(p) tag[p]
#define val(p) val[p]
inline void spread(int p) {
if (!tag(p)) return ;
tag(p<<1)=treap::merge(tag(p), tag(p<<1));
if (leaf[p<<1]) treap::rot[val(p<<1)]=treap::merge(tag(p), treap::rot[val(p<<1)]);
tag(p<<1|1)=treap::merge(tag(p), tag(p<<1|1));
if (leaf[p<<1|1]) treap::rot[val(p<<1|1)]=treap::merge(tag(p), treap::rot[val(p<<1|1)]);
tag(p)=0;
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r; val(p)=++tot;
if (l==r) {leaf[p]=1; return ;}
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int l, int r, int dat) {
if (l<=tl(p)&&r>=tr(p)) {tag(p)=treap::merge(treap::rot[dat], tag(p)); if (tl(p)==tr(p)) treap::upd(val(p), dat); return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) upd(p<<1, l, r, dat);
if (r>mid) upd(p<<1|1, l, r, dat);
}
int query(int p, int pos) {
if (tl(p)==tr(p)) return val(p);
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) return query(p<<1, pos);
else return query(p<<1|1, pos);
}
}
namespace seg2{
int tl[N2<<2], tr[N2<<2], val[N2<<2], tag[N2<<2];
#define pushup(p) val(p)=min(val(p<<1), val(p<<1|1))
inline void spread(int p) {
if (!tag(p)) return ;
val(p<<1)+=tag(p); tag(p<<1)+=tag(p);
val(p<<1|1)+=tag(p); tag(p<<1|1)+=tag(p);
tag(p)=0;
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) return ;
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
}
void upd(int p, int pos, int dat) {
if (tl(p)==tr(p)) {val(p)=dat; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (pos<=mid) upd(p<<1, pos, dat);
else upd(p<<1|1, pos, dat);
pushup(p);
}
void upd(int p, int l, int r, int dat) {
if (l<=tl(p)&&r>=tr(p)) {val(p)+=dat; tag(p)+=dat; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) upd(p<<1, l, r, dat);
if (r>mid) upd(p<<1|1, l, r, dat);
pushup(p);
}
int query(int p, int l, int r) {
if (l<=tl(p)&&r>=tr(p)) return val(p);
spread(p);
int mid=(tl(p)+tr(p))>>1, ans=INF;
if (l<=mid) ans=min(ans, query(p<<1, l, r));
if (r>mid) ans=min(ans, query(p<<1|1, l, r));
return ans;
}
}
int qlcp() {int ans=0; for (; s[0][ans+1]&&s[0][ans+1]==s[1][ans+1]; ++ans); return ans;}
int qlcp(int a, int b) {
a=seg1::query(1, a);
b=seg1::query(1, b);
int l=0, r=min(treap::qsiz(a), treap::qsiz(b)), mid;
while (l<=r) {
mid=(l+r)>>1;
if (treap::query(a, mid)==treap::query(b, mid)) l=mid+1;
else r=mid-1;
}
return l-1;
}
signed main()
{
random_device seed;
srand(seed());
// cout<<double(sizeof(op)*3+sizeof(pw)+sizeof(treap::rot)+sizeof(treap::tr)+sizeof(seg1::tl)*8)/1000/1000<<endl; return 0;
scanf("%d%d", &n, &m);
pw[0]=1;
for (int i=1; i<600010; ++i) pw[i]=pw[i-1]*base;
seg1::build(1, 1, n); seg2::build(1, 1, n);
for (int i=1,t; i<=n; ++i) {
scanf("%s", s[i&1]+1);
t=seg1::query(1, i);
treap::upd(t, s[i&1]);
if (i>1) seg2::upd(1, i, qlcp());
}
for (int i=1,l,r; i<=m; ++i) {
// cout<<"i: "<<i<<endl;
// cout<<"tot: "<<tot<<' '<<treap::tot<<endl;
// cout<<"cnt: "<<cnt<<endl;
scanf("%s%d%d", op, &l, &r);
if (*op=='Q') {
if (l==r) printf("%d\n", treap::qsiz(seg1::query(1, l)));
else printf("%d\n", seg2::query(1, l+1, r));
}
else {
scanf("%s", s[0]+1);
treap::upd(++tot, s[0]);
seg1::upd(1, l, r, tot);
if (l>1) seg2::upd(1, l, qlcp(l-1, l));
if (r<n) seg2::upd(1, r+1, qlcp(r, r+1));
if (l+1<=r) seg2::upd(1, l+1, r, strlen(s[0]+1));
}
}
// cout<<"tot: "<<tot<<' '<<treap::tot<<endl;
// for (int i=1; i<=n; ++i) {
// int t=seg1::query(1, i);
// treap::show(treap::rot[t]); cout<<endl;
// }
// cout<<"seg: "; for (int i=1; i<=n; ++i) cout<<seg2::query(1, i, i)<<' '; cout<<endl;
return 0;
}