P9016 题解
P9016 题解
题面
思路
发现如果暴力去做的话每一次修改长度就会增长许多,直接维护是不行的,那就要思考如何维护能让空间在 \(O(\sum|S|)\) 左右。
考虑维护 \(26\) 个 DAG,每一个 DAG 表示每一个字母会变成什么,且在每个 DAG 中的每个点出度只有 \(2\)。
我们维护每一个 DAG 的起点,从后往前做,对于一个字符 \(c\) 要变成字符串 \(s\)(以下为 \(s\) 编号为 \(0,1,\cdots,|s|-1\)),有两种情况。
- \(|s|=1\),那么直接让 \(c\) 的起点变成 \(s_0\) 就好了。
- \(|s|\neq1\),那么我们从 \(0,1,\cdots,|s|-1\) 开始两两合并,第 \(i\) 次合并,先建一个虚点,连向上一个虚点(当第一次合并时则是 \(s_0\) 的起点)和 \(s_i\) 的起点,最后把 \(c\) 的起点更新为最后一个虚点。
这样其实就相当于多次重复调用初始指向自己的节点,可以利用 b 化成 bbb 来理解。

而从后往前做能保证每一次合并的时候,每个字母起点往下的 DAG 都是已经统计好的。
现在开始考虑输出,输出的就是以 a 为起点往下输出 \([l,r]\) 的区间,这其实类似平衡树,我们可以统计每一个点左边和右边连向的 DAG 的大小,这样假设我们要输出以 \(p\) 为根的子树中的 \([l,r]\),有两种情况。
- 左边的 DAG 的大小大于等于 \(l\),那么说明区间有一部分在左边的 DAG 中。
- 左边的 DAG 的大小小于 \(r\),那么说明有一部分在右边的 DAG 中。
递归下去即可。
这边要注意一个细节,因为字符串总长度增长过快,左右 DAG 的大小可能会爆 long long,所以可以设置一个极大值和大小取 min,这样问题就解决了。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
// #pragma GCC optimize(2)
// #pragma GCC optimize(3)
// #define gc getchar
#define gc()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#define FILE(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define FIN(s) freopen(s".in","r",stdin);
#define FOUT(s) freopen(s".out","w",stdout);
#define ll long long
#define re register int
#define rl register ll
#define il inline
using namespace std;
const ll MN=2e5+5,INF=2e18;
ll l,r,n,rt[30],idx;
string s[MN];
char buf[1<<23],*p1=buf,*p2=buf,c[MN];
struct dag{char ch;ll ls,rs,sz;}t[MN<<1];
il void write(rl n){if(n<0){putchar('-');write(-n);return;}if(n>9)write(n/10);putchar(n%10+'0');}
il ll read(){ll x=0,f=1;char ch=gc();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}return x*f;}
il void print(ll p, ll l, ll r){
if(t[p].ch!='~'){putchar(t[p].ch);return;}
if(t[t[p].ls].sz>=l) print(t[p].ls,l,min(r,t[t[p].ls].sz));
if(t[t[p].ls].sz<r) print(t[p].rs,max(l-t[t[p].ls].sz,1ll),r-t[t[p].ls].sz);
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>l>>r>>n;
for(re i=1; i<=n; ++i) cin>>c[i]>>s[i];
for(re i=0; i<26; ++i) t[rt[i]=++idx]={i+'a',0,0,1};
for(re i=n; i; --i){
ll p=rt[s[i][0]-'a'];
for(re j=1; j<s[i].size(); ++j){
ll x=s[i][j]-'a';
t[++idx]={'~',p,rt[x],min(INF,t[p].sz+t[rt[x]].sz)};
p=idx;
}
rt[c[i]-'a']=p;
}print(rt[0],l,r);
return 0;
}//250815

浙公网安备 33010602011771号