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的增大 那么负图上的边会逐渐加进来 一条边被加进来当且仅当 其权值小于 ... 
随机推荐
- hbase2.1.9 centos7 完全分布式 搭建随记
			hbase2.1.9 centos7 完全分布式 搭建随记 这里是当初在三个ECS节点上搭建hadoop+zookeeper+hbase+solr的主要步骤,文章内容未经过润色,请参考的同学搭配其他博 ... 
- 【线型DP】【LCS】UVA_10635 Prince and Princess
			嘤嘤嘤,我又来了,刚A完就写,这个沙雕题有丶恶心. ???时间4.11发现所有表情包都莫得了 题目: In an n×n chessboard, Prince and ... 
- 洛谷  P3627 [APIO2009]抢掠计划  Tarjan缩点+Spfa求最长路
			题目地址:https://www.luogu.com.cn/problem/P3627 第一次寒假训练的结测题,思路本身不难,但对于我这个码力蒟蒻来说实现难度不小-考试时肛了将近两个半小时才刚肛出来. ... 
- NOIP 2016 洛谷 P2827 蚯蚓 题解
			题目传送门 展开 题目描述 本题中,我们将用符号[c]表示对c向下取整,例如:[3.0」= [3.1」=[3.9」=3.蛐蛐国最近蚯蚓成灾了!隔壁跳 蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手 ... 
- JVM内存管理——总结篇
			JVM内存管理--总结篇 自动内存管理--总结篇 内存划分及作用 常见问题 内存划分及作用 程序计数器 线程私有.字节码行号指示器. 执行Java方法,计数器记录的是字节码指令地址:执行本地(Nati ... 
- Flask路由中使用正则表达式匹配
			1.说明 由于flask并不支持直接使用正则表达式来匹配路由,我们可以使用werkzeug.routing的BaseConverter来实现 2.代码 from flask import Flask ... 
- 央行数字货币(CBDCs)的互操作性至关重要
			CBDCs(央行数字货币)将在我们的有生之年产生重大的金融转变.然而,除非这些工具吸取了法定货币的教训,否则创新将毫无意义.互操作性一直是影响CBDC采用和功能的最重要障碍之一.因此,各国央行在这一理 ... 
- 阿里云上安装启动nginx 以及在个人电脑上通过公网ip访问遇到的问题
			1.安装依赖包 //一键安装上面四个依赖 yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel 2.下载并解压安装包 ... 
- CSS的引入与选择器
			CSS的引入与选择器 CSS与HTML的关系 Cascading Style Sheet 即层叠样式表 在上一篇文中,已经介绍了一些非常常用的HTML标签,接下来将步入CSS的学习,如果将单纯HTML ... 
- python 爬虫:HTTP ERROR 406
			解决方法: 设置了Accept头后解决了,但是还是不知道原因 headers:{ Accept:"text/html, application/xhtml+xml, */*" }原 ... 
