templates
templates
前言
2024.11.25 此文用于整理板子
字符串
KMP
namespace KMP {
constexpr int N=1e6+7;
char s[N],t[N];
int lens,lent;
int nxt[N];// 后缀 i 的 border 长度
void main() {
sf("%s%s",s+1,t+1);
lens=strlen(s+1), lent=strlen(t+1);
rep(i,2,lent) {
int &p=nxt[i]=nxt[i-1];
while(p && t[i]!=t[p+1]) p=nxt[p];
if(t[i]==t[p+1]) ++p;
}
int itt=0;// 已经匹配了 itt 位
rep(i,1,lens) {
while(itt && s[i]!=t[itt+1]) itt=nxt[itt];
if(s[i]==t[itt+1]) ++itt;
if(itt==lent) pf("%d\n",i-lent+1);
}
rep(i,1,lent) pf("%d ",nxt[i]);
}
}
manacher
namespace manacher {
constexpr int N=1.1e7+7;
int n;
char s[N],t[N<<1];
void init() {
t[1]='#', t[2]='$';
rep(i,1,n) t[(i<<1)+1]=s[i], t[(i<<1|1)+1]='$';
t[(n<<1|1)+2]='&';
}
int p[N<<1];
int m;
int ans;
int r,mid;
void solve() {
r=mid=1;
rep(i,2,m) {
int j=(mid<<1)-i;
if(i<=r) p[i]=min(p[j],r-i);
while(t[i-p[i]-1] == t[i+p[i]+1]) ++p[i];
if(p[i]+i>r) r=p[i]+i, mid=i;
ans=max(ans,p[i]);
}
}
void main() {
sf("%s",s+1);
n=strlen(s+1);
init();
m=(n<<1|1)+2;
solve();
pf("%d\n",ans);
}
}
SA 后缀数组
namespace SA {
constexpr int N=1e6+7;
char s[N];
int n,m,p;
int rk[N],sa[N];
int tmprk[N];
int cnt[N];
int id[N];
void main() {
sf("%s",s+1);
n=strlen(s+1);
m=128;
rep(i,1,n) cnt[rk[i]=s[i]]++;
rep(i,1,m) cnt[i]+=cnt[i-1];
per(i,n,1) sa[cnt[rk[i]]--]=i;
for(int w=1;;w<<=1,m=p) {
int cur=0;
rep(i,n-w+1,n) id[++cur]=i;
rep(i,1,n) if(sa[i]>w) id[++cur]=sa[i]-w;
memset(cnt,0,sizeof(cnt));
rep(i,1,n) cnt[rk[i]]++;
rep(i,1,m) cnt[i]+=cnt[i-1];
per(i,n,1) sa[cnt[rk[id[i]]]--]=id[i];
p=0;
memcpy(tmprk,rk,sizeof(rk));
rep(i,1,n) {
if(tmprk[sa[i]]==tmprk[sa[i-1]] && tmprk[sa[i]+w]==tmprk[sa[i-1]+w]) rk[sa[i]]=p;
else rk[sa[i]]=++p;
}
if(p==n) break;
}
rep(i,1,n) pf("%d ",sa[i]);
}
}
SAM 后缀自动机
struct sam {
int last=1,cnt=1;
int ch[N<<1][26],fa[N<<1],l[N<<1];
void insert(int c) {
int p=last,np=++cnt;
last=np;
l[np]=l[p]+1;
for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else {
int q=ch[p][c];
if(l[p]+1==l[q]) fa[np]=q;
else {
int nq=++cnt;
l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q],fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
size[np]=1;
}
};
数学
线性代数
线性基(插入)
int n;
ll a,p[N];
void insert(ll x) {
per(i,bit,0) {
if(!(x&(1ll<<i))) continue;
if(!p[i]) return p[i]=x, void(0);
x^=p[i];
}
}
行列式
void _swap(int x,int y) {
rep(i,1,n) swap(a[x][i],a[y][i]);
f^=1;
}
void gauss() {
rep(i,1,n) {
rep(j,i+1,n) {
while(a[i][i]) {
int K=a[j][i]/a[i][i];
rep(k,i,n) {
_add(a[j][k],p-mul(K,a[i][k]));
}
_swap(i,j);
}
_swap(i,j);
}
}
}
int calc() {
int ans=1;
rep(i,1,n) _mul(ans,a[i][i]);
return f ? add(p,-ans) : ans;
}
void main() {
sf("%d%d",&n,&p);
rep(i,1,n) rep(j,1,n) sf("%d",&a[i][j]), (a[i][j]+=p)%=p;
gauss();
pf("%d\n",calc());
}
多项式
FWT
函数:
void calc() { rep(i,0,n-1) _mul(a[i],b[i]); }
void OR(int *f,int x=1) {
for(int o=2,k=1; o<=n; o<<=1,k<<=1)
for(int i=0; i<n; i+=o)
rep(j,0,k-1) _add(f[i+j+k],mul(f[i+j],x));
}
void AND(int *f,int x=1) {
for(int o=2,k=1; o<=n; o<<=1,k<<=1)
for(int i=0; i<n; i+=o)
rep(j,0,k-1) _add(f[i+j],mul(f[i+j+k],x));
}
void XOR(int *f,int x=1) {
for(int o=2,k=1; o<=n; o<<=1,k<<=1)
for(int i=0; i<n; i+=o)
rep(j,0,k-1)
_add(f[i+j],f[i+j+k]), f[i+j+k]=add(f[i+j],mod-add(f[i+j+k],f[i+j+k])), _mul(f[i+j],x), _mul(f[i+j+k],x);
}
调用方式:
OR(a), OR(b), calc(), OR(a,mod-1);
AND(a), AND(b), calc(), AND(a,mod-1);
XOR(a), XOR(b), calc(), XOR(a,ksm(2));
数据结构
线段树
zkw 线段树
struct zkw {
int p;
ll sum[N<<2],tag[N<<2];
void pushup(int u,int siz) { sum[u]=sum[u<<1]+sum[u<<1|1]+tag[u]*siz; }
void build() {
p=1;
while(p-2<n) p<<=1;
rep(i,1,n) sum[p+i]=a[i];
per(i,p-1,1) sum[i]=sum[i<<1]+sum[i<<1|1];
}
void update(int l,int r,ll x) {
int L=p+l-1,R=p+r+1;
int siz=1;
while(L^R^1) {
if((L&1)^1) sum[L^1]+=x*siz, tag[L^1]+=x;
if(R&1) sum[R^1]+=x*siz, tag[R^1]+=x;
L>>=1, R>>=1, siz<<=1;
pushup(L,siz),pushup(R,siz);
}
for(L>>=1,siz<<=1;L;L>>=1,siz<<=1) pushup(L,siz);
}
ll query(int l,int r) {
ll s=0;
int L=p+l-1,R=r+p+1;
int sizl=0,sizr=0,siz=1;
while(L^R^1) {
if((L&1)^1) s+=sum[L^1], sizl+=siz;
if(R&1) s+=sum[R^1], sizr+=siz;
L>>=1, R>>=1, siz<<=1;
s+=tag[L]*sizl+tag[R]*sizr;
}
for(L>>=1,sizl+=sizr;L;L>>=1) s+=tag[L]*sizl;
return s;
}
};
平衡树
fhq 平衡树
const int N=1e5+7,V=1e9;
int n;
int opt,x;
mt19937 rd(time(0));
struct node{
int val,pri,siz;
int ch[2];
};
struct fhq_treap{
int cnt,rt;
node tr[N];
int newnode(int x){
tr[++cnt]={x,(int)rd()%V,1};
return cnt;
}
void pushup(int u){
tr[u].siz=tr[tr[u].ch[0]].siz+tr[tr[u].ch[1]].siz+1;
}
void split(int u,int &x,int &y,int w){
if(!u) return x=y=0,void();
if(tr[u].val<=w){
x=u,split(tr[u].ch[1],tr[u].ch[1],y,w);
}else{
y=u,split(tr[u].ch[0],x,tr[u].ch[0],w);
}
pushup(u);
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(tr[x].pri<tr[y].pri) {
tr[x].ch[1]=merge(tr[x].ch[1],y);
pushup(x);
return x;
}else{
tr[y].ch[0]=merge(x,tr[y].ch[0]);
pushup(y);
return y;
}
}
void insert(int w){
int x,y;
split(rt,x,y,w);
rt=merge(x,merge(newnode(w),y));
}
void del(int w){
int x,y;
split(rt,x,y,w);
int z;
split(x,x,z,w-1);
z=merge(tr[z].ch[0],tr[z].ch[1]);
rt=merge(x,merge(z,y));
}
void find_by_key(int w){
int x,y;
split(rt,x,y,w-1);
pf("%d\n",tr[x].siz+1);
rt=merge(x,y);
}
int kth(int u,int k){
if(tr[tr[u].ch[0]].siz+1==k) return tr[u].val;
if(k<=tr[tr[u].ch[0]].siz) return kth(tr[u].ch[0],k);
return kth(tr[u].ch[1],k-tr[tr[u].ch[0]].siz-1);
}
void find_by_rank(int k){
pf("%d\n",kth(rt,k));
}
void find_pre(int w){
int x,y;
split(rt,x,y,w-1);
int now=x;
while(tr[now].ch[1]) now=tr[now].ch[1];
pf("%d\n",tr[now].val);
rt=merge(x,y);
}
void find_next(int w){
int x,y;
split(rt,x,y,w);
int now=y;
while(tr[now].ch[0]) now=tr[now].ch[0];
pf("%d\n",tr[now].val);
rt=merge(x,y);
}
};
树套树
线段树套平衡树
namespace shutaoshu {
constexpr int N=5e4+7,V=1e8,inf=2147483647;
int n,m;
int a[N];
int opt;
int l,r,pos,k;
mt19937 rd(random_device{}());
struct node {
int val,rk;
int siz;
int ls,rs;
}tr[N*60];
int cnt;
int newnode(int val) { tr[++cnt]={val,(int)rd(),1}; return cnt; }
struct fhq_tree {
int rt;
void pushup(int u) { tr[u].siz=tr[tr[u].ls].siz+tr[tr[u].rs].siz+1; }
void split(int u,int &x,int &y,int w) {// 将小于等于 w 的分到 x,大于 w 的分到 y
if(!u) return x=y=0, void(0);
if(tr[u].val<=w) {
x=u, split(tr[u].rs,tr[u].rs,y,w);
} else {
y=u, split(tr[u].ls,x,tr[u].ls,w);
}
pushup(u);
}
int merge(int x,int y) {
if(!x || !y) return x+y;
if(tr[x].rk < tr[y].rk) {
tr[x].rs=merge(tr[x].rs,y);
pushup(x);
return x;
} else {
tr[y].ls=merge(x,tr[y].ls);
pushup(y);
return y;
}
}
void insert(int val) {// 插入值 val
int x,y;
split(rt,x,y,val);
rt=merge(x,merge(newnode(val),y));
}
void delback(int &u) {// 删除平衡树最大的节点
if(!tr[u].rs) return u=tr[u].ls, void(0);
delback(tr[u].rs);
pushup(u);
}
void del(int val) {// 删除值 val
int x,y;
split(rt,x,y,val);
delback(x);
rt=merge(x,y);
}
int query(int u,int w) {// 返回 u 的子树中小于等于 w 的值的个数
if(!u) return 0;
if(tr[u].val<=w) return tr[tr[u].ls].siz+1+query(tr[u].rs,w);
return query(tr[u].ls,w);
}
int get_pre(int val) {// 找严格小于 val 的前驱
int x,y;
split(rt,x,y,val-1);
int p=x;
while(tr[p].rs) p=tr[p].rs;
int ans;
if(p) ans=tr[p].val;
else ans=-inf;
rt=merge(x,y);
return ans;
}
int get_nex(int val) {// 找严格大于 val 的后继
int x,y;
split(rt,x,y,val);
int p=y;
while(tr[p].ls) p=tr[p].ls;
int ans;
if(p) ans=tr[p].val;
else ans=inf;
rt=merge(x,y);
return ans;
}
};
struct segtree {
fhq_tree tr[N<<2];
void build(int u=1,int l=1,int r=n) {
rep(i,l,r) tr[u].insert(a[i]);
if(l==r) return;
int mid=(l+r)>>1;
build(u<<1,l,mid), build(u<<1|1,mid+1,r);
}
int query(int L,int R,int val,int u=1,int l=1,int r=n) {// 返回区间小于等于 val 的元素个数
if(l>=L && r<=R) return tr[u].query(tr[u].rt,val);
int s=0;
int mid=(l+r)>>1;
if(L<=mid) s+=query(L,R,val,u<<1,l,mid);
if(mid+1<=R) s+=query(L,R,val,u<<1|1,mid+1,r);
return s;
}
void change(int pos,int val,int u=1,int l=1,int r=n) {
tr[u].del(a[pos]), tr[u].insert(val);
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) change(pos,val,u<<1,l,mid);
else change(pos,val,u<<1|1,mid+1,r);
}
int get_pre(int L,int R,int val,int u=1,int l=1,int r=n) {
if(l>=L && r<=R) return tr[u].get_pre(val);
int mid=(l+r)>>1;
int s=-inf;
if(L<=mid) s=get_pre(L,R,val,u<<1,l,mid);
if(mid+1<=R) s=max(s,get_pre(L,R,val,u<<1|1,mid+1,r));
return s;
}
int get_nex(int L,int R,int val,int u=1,int l=1,int r=n) {
if(l>=L && r<=R) return tr[u].get_nex(val);
int mid=(l+r)>>1;
int s=inf;
if(L<=mid) s=get_nex(L,R,val,u<<1,l,mid);
if(mid+1<=R) s=min(s,get_nex(L,R,val,u<<1|1,mid+1,r));
return s;
}
}T;
void init() {
T.build();
}
int get_rk_by_val(int l,int r,int val) {
return T.query(l,r,val-1)+1;
}
int get_val_by_rk(int l,int r,int k) {
int L=0,R=V;
while(L<R) {
int mid=(L+R+1)>>1;
if(get_rk_by_val(l,r,mid)>k) R=mid-1;
else L=mid;
}
return L;
}
void change_val_by_pos(int pos,int val) {
T.change(pos,val);
a[pos]=val;
}
int get_pre_by_val(int l,int r,int val) {
return T.get_pre(l,r,val);
}
int get_nex_by_val(int l,int r,int val) {
return T.get_nex(l,r,val);
}
void main() {
sf("%d%d",&n,&m);
rep(i,1,n) sf("%d",&a[i]);
init();
rep(i,1,m) {
sf("%d",&opt);
switch (opt) {
case 1 : sf("%d%d%d",&l,&r,&k); pf("%d\n",get_rk_by_val(l,r,k)); break;
case 2 : sf("%d%d%d",&l,&r,&k); pf("%d\n",get_val_by_rk(l,r,k)); break;
case 3 : sf("%d%d",&pos,&k); change_val_by_pos(pos,k); break;
case 4 : sf("%d%d%d",&l,&r,&k); pf("%d\n",get_pre_by_val(l,r,k)); break;
case 5 : sf("%d%d%d",&l,&r,&k); pf("%d\n",get_nex_by_val(l,r,k)); break;
}
}
}
}
树论
树链剖分
重链剖分
struct tree {
int fa[N],siz[N],gson[N],dep[N];
int dfn[N],eddfn[N],cnt,idfn[N];
int top[N];
void dfs(int u,int f) {
fa[u]=f;
dep[u]=dep[f]+1;
siz[u]=1;
for(int i=head[u]; i; i=e[i].ne) {
int v=e[i].to;
if(v==f) continue;
dfs(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[gson[u]]) gson[u]=v;
}
}
void dfs(int u) {
dfn[u]=eddfn[u]=++cnt;
idfn[cnt]=u;
if(gson[u]) top[gson[u]]=top[u], dfs(gson[u]);
for(int i=head[u]; i; i=e[i].ne) {
int v=e[i].to;
if(v==fa[u] || v==gson[u]) continue;
top[v]=v, dfs(v);
}
eddfn[u]=cnt;
}
int tr[N<<2],tag[N<<2];
int p;
void build() {
p=1;
while(p-2<n) p<<=1;
rep(i,1,n) tr[p+i]=a[idfn[i]];
per(i,p-1,1) tr[i]=add(tr[i<<1],tr[i<<1|1]);
}
void init() {
dfs(rt,0);
top[rt]=rt;
dfs(rt);
build();
}
void maketag(int u,int x,int siz) { _add(tr[u],1ll*x*siz%mod), _add(tag[u],x); }
void pushup(int u,int siz) { tr[u]=add(add(tr[u<<1],tr[u<<1|1]),1ll*siz*tag[u]%mod); }
void _update(int l,int r,int x) {
l=p+l-1, r=p+r+1;
int siz=1;
while(l^r^1) {
if((l&1)^1) maketag(l^1,x,siz);
if(r&1) maketag(r^1,x,siz);
l>>=1, r>>=1, siz<<=1;
pushup(l,siz), pushup(r,siz);
}
for(l>>=1, siz<<=1; l; l>>=1, siz<<=1) pushup(l,siz);
}
int _query(int l,int r) {
l=p+l-1, r=p+r+1;
int sizl=0,sizr=0,siz=1;
int s=0;
while(l^r^1) {
if((l&1)^1) _add(s,tr[l^1]), sizl+=siz;
if(r&1) _add(s,tr[r^1]), sizr+=siz;
l>>=1, r>>=1, siz<<=1;
_add(s,1ll*tag[l]*sizl%mod), _add(s,1ll*tag[r]*sizr%mod);
}
for(l>>=1, sizl+=sizr; l; l>>=1) _add(s,1ll*tag[l]*sizl%mod);
return s;
}
void update(int u,int v,int x) {
while(top[u]^top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
_update(dfn[top[u]],dfn[u],x), u=fa[top[u]];
}
if(dfn[u]>dfn[v]) swap(u,v);
_update(dfn[u],dfn[v],x);
}
void update(int u,int x) {
_update(dfn[u],eddfn[u],x);
}
int query(int u,int v) {
int s=0;
while(top[u]^top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
_add(s,_query(dfn[top[u]],dfn[u])), u=fa[top[u]];
}
if(dfn[u]>dfn[v]) swap(u,v);
_add(s,_query(dfn[u],dfn[v]));
return s;
}
int query(int u) {
return _query(dfn[u],eddfn[u]);
}
};
图论
连通性相关
割点和桥
桥
void tarjan(int rt,int u,int f) {
dfn[u]=low[u]=++cnt;
for(int v : to[u]) {
if(!dfn[v]) {
tarjan(rt,v,u), low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]) ans.push_back({u,v});
}else if(v!=f) low[u]=min(low[u],dfn[v]);
}
}
割点
void tarjan(int rt,int u,int f) {
dfn[u]=low[u]=++cnt;
int son=0;
for(int v : to[u]) {
if(!dfn[v]) {
++son, tarjan(rt,v,u), low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u] && u!=rt && !isans[u]) isans[u]=1, ans.push_back(u);
}else if(v!=f) low[u]=min(low[u],dfn[v]);
}
if(son>=2 && u==rt) isans[u]=1, ans.push_back(u);
}
强连通分量
void tarjan(int u) {
dfn[u]=low[u]=++dfn0;
st[++top]=u;
for(int v : to[u]) {
if(!dfn[v]) {
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(!num[v]) {
low[u]=min(low[u],low[v]);//与 dfn[v] 等价
}
}
if(low[u]==dfn[u]) {
++cnt;
while(st[top+1]!=u) scc[cnt].push_back(st[top]), num[st[top]]=cnt, --top;
}
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18567704