题解 [CF1286E] Fedya the Potter Strikes Back
感冒了头好痛,不想写题解
发现就是要在线加入长度为 \(i\) 时每个 border 的贡献
发现在处理到 \(i\) 时的最长 border 是可以求出来的
但是这个东西在 KMP 的失配树上和 \(i-1\) 的甚至可以不在同一条链上,变化量巨大
然而注意到这样一个性质就好做了:
从 \(i-1\) 变化到 \(i\) 实际上是删除了一些 \(s_{r+1}\neq s_i\) 的 border \(s_{l, r}\)
同时将剩下的 border 的权值和 \(w_i\) 取 \(\min\)
先看怎么删除:
我们需要 \(O(1)\) 的找到下一个能删除的 border,那么在失配树上记录每个点的父亲及第一个 下一个字符与当前 border 的下一个字符不同 的祖先
这个东西是容易维护的
然后取 \(\min\)
一个想法是用权值线段树之类的东西
但发现如果暴力合并的话每将一个权值取 \(\min\) 颜色数会减少 1
而每加入一个 \(i\) 只会带来 1 的颜色数
所以用一个 map 暴力复杂度是均摊 \(O(n\log n)\) 的
于是这样总复杂度就是 \(O(n\log n)\) 了
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 600010
#define fir first
#define sec second
#define ll long long
#define int128 __int128
// #define int long long
char buf[N]; int btop;
void writeln(int128 t) {
do {buf[++btop]='0'+t%10; t/=10;} while (t);
while (btop) printf("%c", buf[btop--]);
printf("\n");
}
int n;
char s[N];
ll w[N], bit[N];
int128 ans, sum;
map<ll, int> mp;
const ll mask=(1<<30)-1;
int fa[N], top[N], nxt[N], tot;
inline void upd(int i, ll val) {for (; i; i-=i&-i) bit[i]=min(bit[i], val);}
inline int query(int i) {ll ans=INF; for (; i<=n; i+=i&-i) ans=min(ans, bit[i]); return ans;}
signed main()
{
scanf("%d", &n);
memset(bit, 0x3f, sizeof(bit));
for (int i=1,j=0; i<=n; ++i) {
// cout<<"i: "<<i<<endl;
scanf("%s%lld", &s[i], &w[i]);
s[i]='a'+((s[i]-'a')+ans)%26, w[i]^=(ans&mask);
// cout<<s[i]<<' '<<w[i]<<endl;
if (fa[i-1]) top[i-1]=s[i]==s[fa[i-1]+1]?top[fa[i-1]]:fa[i-1];
if (s[i]==s[1]) ++mp[w[i]], sum+=w[i];
// cout<<"sum: "<<(ll)sum<<endl;
for (int now=i-1; now; now=(s[now+1]==s[i])?top[now]:fa[now]) if (s[now+1]!=s[i]) {
ll val=query(i-now);
--mp[val], sum-=val;
}
upd(i, w[i]);
if (i!=1) {
while (j&&s[j+1]!=s[i]) j=nxt[j];
if (s[j+1]==s[i]) ++j;
nxt[i]=j;
}
fa[i]=nxt[i];
for (map<ll, int>::iterator it; (it=mp.upper_bound(w[i]))!=mp.end(); mp.erase(it))
mp[w[i]]+=it->sec, sum-=1ll*(it->fir-w[i])*it->sec;
ans+=sum;
writeln(ans);
}
return 0;
}