题解 无聊的游戏

传送门

神仙题,想不到,而且空间卡不过去

首先发现区间加字符串这个操作令人智熄至极
第一思路是离线什么的把这个搞掉
然后看一眼她要查询啥:区间 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;
}
posted @ 2022-01-14 21:06  Administrator-09  阅读(0)  评论(0编辑  收藏  举报