[Str记录]CF1286E Fedya the Potter Strikes Back
command_block · · 个人记录
题意 : 给定一个字符串
你需要完成
定义一个子区间
每次操作后,你都要求出当前的串的所有子区间的可疑度之和。
强制在线,
鸽了大半年的题 /cy
不难发现题意等价于动态 push_back 并维护
考虑动态维护
当加入字符
-
对于原有的
\rm Bd ,若对应前缀的下一个字符不是c ,则会消失。 -
若
S_1=S_i 则新增一个长度为1 的\rm Bd 。
(由于加入
如何快速找到该删除那些
原串的
记节点
记节点
需要删除的节点即为终止链上
找到未被删除的最长
当加入
若
接下来需要维护权值总和。
对于剩下未删除的
需要我们维护这样的一个数据结构 : 支持删除,插入,全体取
用 std::map 维护每个权值及其出现次数,暴力取
删除某个
时间复杂度
答案可能爆 long long ,需要 __int128。
#include<algorithm>
#include<cstdio>
#include<map>
#define lll __int128
#define MaxN 600500
using namespace std;
const lll mask=(1<<30)-1;
struct MinDS
{
struct Data{int x,p;}stk[MaxN];
int top,n;
void pb(int x){
while(top&&stk[top].x>=x)top--;
stk[++top]=(Data){x,++n};
}
int qry(int tl)
{
int l=1,r=top,mid;
while(l<r){
mid=(l+r)>>1;
if (stk[mid].p<tl)l=mid+1;
else r=mid;
}return stk[r].x;
}
}T;
map<int,int> o;
lll ans,now;
void del(int tl){
int w=T.qry(tl);
now-=w;o[w]--;
}
#define fir first
#define sec second
void tmin(int w)
{
if (o.empty())return ;
map<int,int>::iterator it,it2=o.end();it2--;
int cnt=0;
while(1){
it=it2;
if (it->fir<=w)break;
cnt+=it->sec;
now-=1ll*it->sec*it->fir;
if (it==o.begin())
{o.erase(it);break;}
else {
it2=it;it2--;
o.erase(it);
}
}o[w]+=cnt;
now+=1ll*w*cnt;
}
int n,fa[MaxN],dif[MaxN];
char s[MaxN];
void print(lll n)
{
if (n==0){puts("0");return ;}
int s[105],tot=0;
while(n){s[++tot]=n%10;n/=10;}
for (int i=tot;i;i--)printf("%d",s[i]);
puts("");
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++){
int w;
scanf("%s%d",&s[i],&w);
s[i]=(s[i]-'a'+ans)%26+'a';
w^=(ans&mask);
if (i>1)
dif[i-1]=(s[i]==s[fa[i-1]+1]) ? dif[fa[i-1]] : fa[i-1];
int u=fa[i-1];
while(u){
if (s[u+1]!=s[i]){del(i-u);u=fa[u];}
else {
if (!fa[i])fa[i]=u+1;
u=dif[u];
}
}
if (i>1&&s[1]==s[i]){
o[w]++;now+=w;
if (!fa[i])fa[i]=1;
}
T.pb(w);tmin(w);
ans+=(now+T.stk[1].x);
print(ans);
}return 0;
}