LibreOJ 3055 「HNOI2019」JOJO

首先显然往 KMP 想,但是好像没有限制总长诶那怎么办呢(
考虑把 (x,c) 这个二元组看做一个字符。

求 Fail 的时候除了第一个二元组,别的二元组都要完全匹配。
因为如果仅是 c 相同而 x 不同,下一个字符一定匹配不上,没有什么用。
但是答案是需要这些贡献的。所以一个 Fail 应当造成一个等差数列的贡献。

诶但是有可持久化怎么办呢(
建个操作树递归处理(在线模拟这个也是可以的,只不过要把操作树上的链可持久化下来)。

诶但是 KMP 复杂度不是均摊的吗怎么办呢(
众所周知 AC 自动机暴力跳 Fail 复杂度是错的,所以我们的做法是直接把失配的边连向失配之后该跳到的状态。
KMP 也可以类似这样做,我们就得到了一个叫 KMP 自动机的东西。

然后主席树维护一下边和贡献就可以了(
具体地,注意到对于 ix 都有一个 li+i 的形式,其中 li 是 Fail 链上在此处深度最大的贡献。
i 拆出来直接算,li 可以用主席树区间赋值维护。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <cstdio>
#include <cassert>
#include <utility>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5;
const int X = 1e4;
const int mod = 998244353;
int n;
int to[N + 5],pre[N + 5],first[N + 5];
inline void add(int u,int v)
{
static int tot = 0;
to[++tot] = v,pre[tot] = first[u],first[u] = tot;
}
struct note
{
int x,c;
} a[N + 5];
int id[N + 5],ans[N + 5],len[N + 5];
int mx[N + 5][26],rt[N + 5][26];
inline int calc(int n)
{
return ((long long)n * (n + 1) >> 1) % mod;
}
struct node
{
int sum,tag;
int nxt;
int ls,rs;
} seg[(N << 7) + 5];
int seg_tot;
inline void push(int p,int tl,int tr)
{
int &tot = seg_tot;
int mid = tl + tr >> 1;
if(seg[p].tag)
seg[++tot] = seg[seg[p].ls],seg[seg[p].ls = tot].sum = (long long)seg[p].tag * (mid - tl + 1) % mod,seg[seg[p].ls].tag = seg[p].tag,
seg[++tot] = seg[seg[p].rs],seg[seg[p].rs = tot].sum = (long long)seg[p].tag * (tr - mid) % mod,seg[seg[p].rs].tag = seg[p].tag,
seg[p].tag = 0;
}
void update(int r,int k,int nxt,int &p,int tl,int tr)
{
int &tot = seg_tot;
seg[++tot] = seg[p],p = tot;
if(tr < r)
{
seg[p].sum = (long long)k * (tr - tl + 1) % mod,seg[p].tag = k;
return ;
}
if(tl == tr)
{
seg[p].sum = (long long)k * (tr - tl + 1) % mod,seg[p].tag = k,seg[p].nxt = nxt;
return ;
}
push(p,tl,tr);
int mid = tl + tr >> 1;
update(r,k,nxt,seg[p].ls,tl,mid);
r > mid && (update(r,k,nxt,seg[p].rs,mid + 1,tr),1);
seg[p].sum = (seg[seg[p].ls].sum + seg[seg[p].rs].sum) % mod;
}
inline pair<int,int> operator+(const pair<int,int> &a,const pair<int,int> &b)
{
return make_pair((a.first + b.first) % mod,a.second | b.second);
}
pair<int,int> query(int r,int p,int tl,int tr)
{
if(tr < r)
return make_pair(seg[p].sum,0);
if(tl == tr)
return make_pair(seg[p].sum,seg[p].nxt);
push(p,tl,tr);
int mid = tl + tr >> 1;
pair<int,int> ret(0,0);
ret = ret + query(r,seg[p].ls,tl,mid);
r > mid && (ret = ret + query(r,seg[p].rs,mid + 1,tr),1);
return ret;
}
int s[N + 5],top;
void dfs(int i)
{
s[++top] = i;
int nxt = 0;
len[i] = (len[s[top - 1]] + a[i].x) % mod;
if(top == 1)
ans[i] = calc(len[i] - 1);
else
{
ans[i] = (ans[i] + calc(min(mx[i][a[i].c],a[i].x))) % mod;
pair<int,int> t = query(a[i].x,rt[i][a[i].c],1,X);
ans[i] = (ans[i] + t.first) % mod,nxt = t.second;
if(!nxt && a[i].c == a[s[1]].c && a[i].x > a[s[1]].x)
nxt = 1,ans[i] = (ans[i] + (long long)a[s[1]].x * max(0,a[i].x - mx[i][a[i].c])) % mod;
}
mx[i][a[i].c] = max(mx[i][a[i].c],a[i].x),update(a[i].x,len[s[top - 1]],top,rt[i][a[i].c],1,X);
for(register int j = first[i];j;j = pre[j])
memcpy(mx[to[j]],mx[s[nxt + 1]],sizeof mx[to[j]]),memcpy(rt[to[j]],rt[s[nxt + 1]],sizeof rt[to[j]]),ans[to[j]] = ans[i],dfs(to[j]);
--top;
}
int main()
{
scanf("%d",&n);
char op,c;
int x;
for(register int i = 1,cur = 0;i <= n;++i)
{
scanf(" %c%d",&op,&x);
if(op == '1')
scanf(" %c",&c),a[i].x = x,a[i].c = c - 'a',add(cur,i),cur = id[i] = i;
else
cur = id[i] = id[x];
}
for(register int i = first[0];i;i = pre[i])
dfs(to[i]);
for(register int i = 1;i <= n;++i)
printf("%d\n",ans[id[i]]);
}

Related Issues not found

Please contact @Alpha1022 to initialize the comment