6.18 省选模拟赛 字符串 LCT SAM
LINK:字符串
看起来很难做 考虑一种暴力 建立SAM后每次查询暴力扫儿子。
期望得分10分。实际得分10分。
另外一种发现每次扫儿子过于暴力 可以每次儿子向上做贡献 每次都暴力向上跳。
期望得分10分。实际得分100分。
由此可以发现玄学的暴力非常的强大 可能这就是所谓的暴力出奇迹吧.
考虑离线:这样就可以把SAM给建出来了 进一步的 每次询问是查询子树和。
每次修改是单点修改 可以利用线段树维护dfs序就做完了。
不过其中存在细节 分裂的节点是影响答案的统计的。
怎么处理分裂的节点?注意到 分裂的节点和当前添加的节点权值无关。
如果对于分裂出来的新节点权值赋值为0 那么这样就不太行。
一个简单的想法 对于分裂出的节点 都拥有自己对应的权值 就行了。
不过这一点很难维护 因为之前的询问可能直接就询问到分裂的节点了。
仔细思考 对于分裂的节点来说 我们在其最初的节点被赋值的时候就把被分裂的节点给赋好值即可。
这样就需要在SAM的建立的时候 对每个节点再标记一个时间戳 然后分裂的时候 直接vector在这个时间戳上打好标记在最初节点赋值的时候一并修改就解决了刚才的问题即可。
难写!!!
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<bitset>
#include<list>
#include<map>
#include<set>
#include<utility>
#include<iomanip>
#define RE register
#define ll long long
#define putl(x) printf("%lld\n",x)
#define gt(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define get(x) x=read()
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define vep(p,n,i) for(int i=p;i<n;++i)
#define fep(n,p,i) for(int i=n;i>=p;--i)
#define pii pari<int,int>
#define mod 998244353
#define f(i) t[i].fa
#define pb push_back
#define zz p<<1
#define yy p<<1|1
#define len(i) t[i].len
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=500010,maxn=50010<<2;
int T,m,n,last=1,cnt=1,mark,len,id,len1;ll ans;
char a[maxn],b[MAXN];
struct wy
{
int fa,len;
int ch[26];
}t[maxn];
vector<int>g[maxn];
int v[maxn],dfn[maxn],s[maxn],out[maxn],lin[maxn],ver[maxn],nex[maxn],pos[maxn],sj[maxn];
ll sum[maxn<<2];
inline void add(int x,int y)
{
ver[++len1]=y;
nex[len1]=lin[x];
lin[x]=len1;
}
inline void insert(int x)
{
int p=last;
int np=last=++cnt;
len(np)=len(p)+1;
while(p&&!t[p].ch[x])
{
t[p].ch[x]=np;
p=f(p);
}
if(!p)f(np)=1;
else
{
int q=t[p].ch[x];
if(len(q)==len(p)+1)f(np)=q;
else
{
int nq=++cnt;
t[nq]=t[q];
len(nq)=len(p)+1;
f(q)=f(np)=nq;
while(p&&t[p].ch[x]==q)
{
t[p].ch[x]=nq;
p=f(p);
}
}
}
}
inline void insert1(int x,int id)
{
int p=last;
int np=last=++cnt;
len(np)=len(p)+1;sj[np]=id;
while(p&&!t[p].ch[x])
{
t[p].ch[x]=np;
p=f(p);
}
if(!p)f(np)=1;
else
{
int q=t[p].ch[x];
if(len(q)==len(p)+1)f(np)=q;
else
{
int nq=++cnt;
t[nq]=t[q];sj[nq]=sj[q];
len(nq)=len(p)+1;
g[sj[q]].pb(nq);
g[sj[q]].pb(len(nq)-len(f(nq)));
g[sj[q]].pb(q);
g[sj[q]].pb(len(q)-len(nq)-(len(q)-len(f(q))));
f(q)=f(np)=nq;
while(p&&t[p].ch[x]==q)
{
t[p].ch[x]=nq;
p=f(p);
}
}
}
g[id].pb(np);
g[id].pb(len(np)-len(f(np)));
}
inline void dfs(int x)
{
ans+=len(x)-len(f(x));
rep(1,cnt,i)if(f(i)==x)dfs(i);
}
inline void ask()
{
int now=1;
rep(1,len,i)
{
if(!t[now].ch[b[i]-'a'])return ans=0,void();
now=t[now].ch[b[i]-'a'];
}
ans=-(len-len(f(now))-1);
dfs(now);
}
inline void build(int p,int l,int r)
{
if(l==r)
{
sum[p]=v[pos[l]];
return;
}
int mid=(l+r)>>1;
build(zz,l,mid);
build(yy,mid+1,r);
sum[p]=sum[zz]+sum[yy];
}
inline void change(int p,int l,int r,int x,int w)
{
if(l==r)
{
sum[p]+=w;
return;
}
int mid=(l+r)>>1;
if(x<=mid)change(zz,l,mid,x,w);
else change(yy,mid+1,r,x,w);
sum[p]=sum[zz]+sum[yy];
}
inline void dfs1(int x)
{
dfn[x]=++id;pos[id]=x;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
dfs1(tn);
}
out[x]=id;
}
inline void change(int x,int w)
{
v[x]+=w;
change(1,1,cnt,dfn[x],w);
}
inline ll ask(int p,int l,int r,int L,int R)
{
if(L<=l&&R>=r)return sum[p];
int mid=(l+r)>>1;
if(R<=mid)return ask(zz,l,mid,L,R);
if(L>mid)return ask(yy,mid+1,r,L,R);
return ask(zz,l,mid,L,R)+ask(yy,mid+1,r,L,R);
}
inline void ask(int x)
{
int now=1;ans=0;
for(int i=0;i<g[x].size();++i)
{
if(!t[now].ch[g[x][i]])return;
now=t[now].ch[g[x][i]];
}
if(!v[now])return;
int w1=len(now);
int w2=g[x].size();
ans=-(w2-1-(len(f(now))+1)+1);
ans+=ask(1,1,cnt,dfn[now],out[now]);
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%s",a+1);n=strlen(a+1);
fep(n,1,i)insert(a[i]-'a');
rep(2,cnt,i)v[i]=len(i)-len(f(i));
mark=cnt;
gt(T);gt(m);
if(m<=100)
{
rep(1,m,i)
{
int op;
gt(op);
if(!op)
{
scanf("%s",b+1);
len=strlen(b+1);
if(len>n){ans=0;put(0);}
else
{
reverse(b+1,b+1+len);
ask();putl(ans);
}
}
else
{
scanf("%s",b+1);++n;
int ww=(b[1]-'a'+ans*T)%26;
insert(ww);
}
}
return 0;
}
if(!T)
{
rep(1,m,i)
{
int op;gt(op);
if(!op)
{
scanf("%s",b+1);
len=strlen(b+1);
reverse(b+1,b+1+len);
rep(1,len,j)g[i].pb(b[j]-'a');
s[i]=op;
}
else
{
scanf("%s",b+1);
int ww=(b[1]-'a')%26;
insert1(ww,i);
s[i]=op;
}
}
rep(2,cnt,i)add(f(i),i);
dfs1(1);
build(1,1,cnt);
for(int i=0;i<g[0].size();i+=2)change(g[0][i],g[0][i+1]);
rep(1,m,i)
{
if(s[i]==0)ask(i),putl(ans);
else for(int j=0;j<g[i].size();j+=2)change(g[i][j],g[i][j+1]);
}
}
return 0;
}
期望得分 50.
这题不强制在线我都A了都。
考虑100分。
容易想到每次加入一个节点要实现断边 连边 维护子树和的功能。
上LCT 直接维护即可。这里不考虑维护子树和 而是每个点向上赋值 深度log咋做都对。
也不太好写 注意细节。
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<bitset>
#include<list>
#include<map>
#include<set>
#include<utility>
#include<iomanip>
#define RE register
#define ll long long
#define putl(x) printf("%lld\n",x)
#define gt(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define get(x) x=read()
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define vep(p,n,i) for(int i=p;i<n;++i)
#define fep(n,p,i) for(int i=n;i>=p;--i)
#define pii pari<int,int>
#define mod 998244353
#define f(i) t[i].fa
#define pb push_back
#define zz p<<1
#define yy p<<1|1
#define len(i) t[i].len
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=500010,maxn=50010<<2;
int T,m,n,last=1,cnt=1,mark,len,id,len1;ll ans;
char a[maxn],b[MAXN];
struct wy{int fa,len;int ch[26];}t[maxn];
struct LCT
{
#define l(x) c[x][0]
#define r(x) c[x][1]
int c[maxn][2],rev[maxn],s[maxn],fa[maxn];
ll v[maxn],tag[maxn];
inline bool pd(int x){return l(fa[x])==x||r(fa[x])==x;}
inline void add(int x,ll y)
{
v[x]+=y;
tag[x]+=y;
}
inline void rever(int x)
{
swap(l(x),r(x));
rev[x]^=1;
}
inline void pushdown(int x)
{
if(rev[x])
{
rever(l(x));
rever(r(x));
rev[x]=0;
}
if(tag[x])
{
v[l(x)]+=tag[x];
v[r(x)]+=tag[x];
tag[l(x)]+=tag[x];
tag[r(x)]+=tag[x];
tag[x]=0;
}
}
inline void rotate(int x)
{
int old=fa[x],oldf=fa[old],k=c[fa[x]][1]==x;
c[old][k]=c[x][k^1];c[x][k^1]=old;
if(pd(old))c[oldf][c[oldf][1]==old]=x;
if(c[old][k])fa[c[old][k]]=old;
fa[x]=oldf;fa[old]=x;
}
inline void splay(int x)
{
int top=0,y=x;
s[++top]=x;
while(pd(y))s[++top]=fa[y],y=fa[y];
while(top)pushdown(s[top--]);
while(pd(x))
{
int old=fa[x];
if(pd(old))rotate(((c[old][0]==x)^(c[fa[old]][0]==old))?x:old);
rotate(x);
}
}
inline void access(int x)
{
for(int y=0;x;x=fa[y=x])
splay(x),c[x][1]=y;
}
inline void make_root(int x)
{
access(x);
splay(x);
rever(x);
}
inline void LINK(int x,int y)
{
make_root(x);
fa[x]=y;
access(x);
}
inline void cutf(int x)
{
access(x);
splay(x);
fa[l(x)]=0;
l(x)=0;
}
inline void cut(int x,int y)
{
make_root(x);
cutf(y);
}
inline void change(int x,int p)
{
make_root(1);
access(x);
splay(x);
add(x,p);
}
inline ll ask(int x)
{
access(x);
splay(x);
return v[x];
}
}R;
inline void insert(int x)
{
int p=last;
int np=last=++cnt;
len(np)=len(p)+1;
while(p&&!t[p].ch[x])
{
t[p].ch[x]=np;
p=f(p);
}
if(!p)
{
f(np)=1;
R.LINK(np,f(np));
}
else
{
int q=t[p].ch[x];
if(len(q)==len(p)+1)
{
f(np)=q;
R.LINK(np,f(np));
}
else
{
int nq=++cnt;
R.change(q,-len(q)+len(f(q)));
t[nq]=t[q];
len(nq)=len(p)+1;
R.LINK(nq,f(nq));
R.v[nq]=R.ask(q);
R.cut(q,f(q));
R.LINK(np,nq);
R.LINK(q,nq);
f(q)=f(np)=nq;
R.change(nq,len(nq)-len(f(nq)));
R.change(q,len(q)-len(f(q)));
while(p&&t[p].ch[x]==q)
{
t[p].ch[x]=nq;
p=f(p);
}
}
}
R.change(np,len(np)-len(f(np)));
}
inline void ask()
{
ans=0;
int now=1;
fep(len,1,i)
{
if(!t[now].ch[b[i]-'a'])return ans=0,void();
now=t[now].ch[b[i]-'a'];
}
ans=R.ask(now)-len+len(f(now))+1;
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%s",a+1);n=strlen(a+1);
fep(n,1,i)insert(a[i]-'a');
gt(T);gt(m);
rep(1,m,i)
{
int op;scanf("%d",&op);
scanf("%s",b+1);
if(!op)
{
len=strlen(b+1);
ask();putl(ans);
}
else insert((b[1]-'a'+ans*T)%26);
}
return 0;
}
6.18 省选模拟赛 字符串 LCT SAM的更多相关文章
- 3.28 省选模拟赛 染色 LCT+线段树
发现和SDOI2017树点涂色差不多 但是当时这道题模拟赛的时候不会写 赛后也没及时订正 所以这场模拟赛的这道题虽然秒想到了LCT和线段树但是最终还是只是打了暴力. 痛定思痛 还是要把这道题给补了. ...
- 6.18 省选模拟赛 树 倍增 LCT
LINK:树 考虑暴力 保存每个版本的父亲 然后暴力向上跳.得分20. 考虑离线 可以离线那么就可以先把树给搞出来 然后考虑求k级祖先 可以倍增求. 如何判断合法 其实要求路径上的边的时间戳<= ...
- 4.17 省选模拟赛 远行 LCT 启发式合并 倍增
容易写出nQ的暴力 由于数据是期望的时间 所以直接dfs可以跑的很快 可以拿到70分. 当然 可以进一步优化暴力 使用换根dp 然后可以将暴力优化到n^2. const int MAXN=300010 ...
- 4.18 省选模拟赛 无聊的计算器 CRT EXBSGS EXLucas
算是一道很毒瘤的题目 考试的时候码+调了3h才搞定. op==1 显然是快速幂. op==2 有些点可以使用BSGS 不过后面的点是EXBSGS. 这个以前学过了 考试的时候还是懵逼.(当时还是看着花 ...
- 5.29 省选模拟赛 波波老师 SAM 线段树 单调队列 并查集
LINK:波波老师 LINK:同bzoj 1396 识别子串 不过前者要求线性做法 后者可以log过.实际上前者也被我一个log给水过了. 其实不算很水 我自认跑的很快罢了. 都是求经过一个位置的最短 ...
- 【洛谷比赛】[LnOI2019]长脖子鹿省选模拟赛 T1 题解
今天是[LnOI2019]长脖子鹿省选模拟赛的时间,小编表示考的不怎么样,改了半天也只会改第一题,那也先呈上题解吧. T1:P5248 [LnOI2019SP]快速多项式变换(FPT) 一看这题就很手 ...
- 18/9/21模拟赛-Updated
18/9/21模拟赛 期望得分:100:实际得分:0 qwq 拿到题目第一眼,我去,这不是洛谷原题(仓鼠找Sugar)吗 又多看了几眼,嗯,对,除了是有多组数据外,就是原题 然后码码码....自以为 ...
- @省选模拟赛03/16 - T3@ 超级树
目录 @description@ @solution@ @accepted code@ @details@ @description@ 一棵 k-超级树(k-SuperTree) 可按如下方法得到:取 ...
- 5.19 省选模拟赛 小B的图 最小生成树 LCT
LINK:小B的图 这道题就比较容易了. 容易想到将询问离线 然后 从小到大排序 那么显然是优先放正图(x+k)的边. 考虑随着x的增大 那么负图上的边会逐渐加进来 一条边被加进来当且仅当 其权值小于 ...
随机推荐
- Pytorch | 详解Pytorch科学计算包——Tensor
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Pytorch专题的第二篇,我们继续来了解一下Pytorch中Tensor的用法. 上一篇文章当中我们简单介绍了一下如何创建一个Ten ...
- css3实现炫酷的文字效果_空心/立体/发光/彩色/浮雕/纹理等文字特效
这篇文章主要整理一些css3实现的一些文字特效,分享给大家, 相信您看完会有不少的收货哦! 一.css3 空心文字 <style> .hollow{ -webkit-text-stroke ...
- 基础设计模式-03 从过滤器(Filter)校验链学习职责链模式
1.职责链路模式 1.1UML图 1.2 职责链路模式的概念 为了避免处理对象的耦合关系,将对象连成一个链,沿着这个链进行访问,直到有一个对象处理位置: 1.3 优点 1.按照一定的顺序执行判断: 2 ...
- NEST教程系列:推断索引名
NEST教程系列:三种推断索引名写法 目录 NEST教程系列:三种推断索引名写法 连接时设置默认索引 设置 .NET 类映射索引名 在创建请求的时候直接显式指定索引名 总结 连接时设置默认索引 构建 ...
- wiremock技术入门
mock用于制作测试桩,是非常好用的自动化测试mock工具 一.下载 进入官网的下载地址: http://wiremock.org/docs/running-standalone/
- 如何用HMS Nearby Service给自己的App添加近距离数据传输功能
当你给朋友发送手机资料时,过了很久进度条却动也不动:当你想发送大文件给同事时,仅一个文件就用光了你所有流量:当你跟朋友乘坐飞机时想一起玩游戏时,却因没有网络无奈放弃. 们生活中似乎经常能遇到这 ...
- idea 项目启动console卡在Connected to the target VM, address: '127.0.0.1:51140', transport: 'socket'不动了
- 项目管理:如何显性管理并提升Story分解能力
引言: 在“DevOps能力之屋(CapabilitiesHouse of DevOps)”中,华为云DevCloud提出(工程方法+最佳实践+生态)×工具平台=DevOps能力.华为云DevClou ...
- p44_IP数据包格式
一.IP数据报格式 二.IP分片 数据链路层每帧可封装数据有上限,IP数据超过的要分片. 标识:同一数据报的分片使用同一标识 标志: 片偏移(13bit):用于还原数据报顺序,指出某片在原分组1中的相 ...
- PyQt5基础控件
QLabel标签 功能:在界面上显示文字.图片.链接等 接口: 方法 描述 setText() 设置显示的内容 setAlignment() 设置文字对齐方式 setToolTip() 设置提示信息 ...