为方便区域赛打印pdf模板,所有代码已经搬家到了github中。
目录:
SAM(*)
SA(*)
PAM(*)
树链剖分(*)
01Trie(*)
ACAM(*)
KMP(*)
LCA(*)
主席树(*)
点分治(*)
kd-Tree(*)
斜率优化DP
最大流Dicnic(*)
最小费用最大流(SPFA)(*)
线段树(*)
dfs靠谱找环
靠谱找凸包(*)
tarjan缩点+点双连通(寻割)+边双连通(寻桥)
虚树(*)
圆方树(*)
FFT(*)
SAM+LCT在线动态维护parent树:
#include<bits/stdc++.h>
#define N 1200005
#define inf 1000000007
using namespace std;
int mask;char s[3000005];
int Q;
string chars;
void gets(int mask){
scanf("%s",s);chars=s;
for(int j=0;j<chars.length();j++){
mask=(mask*131+j)%chars.length();
char t=chars[j];
chars[j]=chars[mask];
chars[mask]=t;
}
}
struct Link_Cut_Tree{
int top,fa[N],c[N][2],val[N],tag[N],q[N];
inline void add(int x,int y){if(x)tag[x]+=y,val[x]+=y;}
inline void pushdown(int x){
int l=c[x][0],r=c[x][1];
if(tag[x]){
add(l,tag[x]);add(r,tag[x]);
tag[x]=0;
}
}
inline bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
inline void rotate(int x){
int y=fa[x],z=fa[y],l,r;
if(c[y][0]==x)l=0;else l=1;r=l^1;
if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
c[y][l]=c[x][r];c[x][r]=y;
}
inline void splay(int x){
int top=1;q[top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
for(int i=top;i;i--)pushdown(q[i]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if((c[z][0]==y)^(c[y][0]==x))rotate(x);
else rotate(y);
}rotate(x);
}
}
void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),c[x][1]=t;}
inline void link(int x,int y){fa[x]=y;access(y);splay(y);add(y,val[x]);}
inline void cut(int x){
access(x);splay(x);add(c[x][0],-val[x]);
fa[c[x][0]]=0;c[x][0]=0;
}
}T;
struct Suffix_AutoMaton{
int l[N],fa[N],ch[N][26];
int cnt,last;
Suffix_AutoMaton(){cnt=1;last=1;}
void ins(int c){
int p=last,np=++cnt;last=np;T.val[np]=1;l[np]=l[p]+1;
for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
if(!p)fa[np]=1,T.link(np,1);
else{
int q=ch[p][c];
if(l[p]+1==l[q])fa[np]=q,T.link(np,q);
else{
int nq=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];T.link(nq,fa[q]);
fa[np]=fa[q]=nq;
T.cut(q);T.link(q,nq);T.link(np,nq);
for(;ch[p][c]==q;p=fa[p])ch[p][c]=nq;
}
}
}
void build(){
scanf("%s",s);int len=strlen(s);
for(int i=0;i<len;i++)ins(s[i]-'A');
}
int query(){
gets(mask);
int p=1;int len=chars.length();
for(int i=0;i<len;i++)if(!(p=ch[p][chars[i]-'A']))return 0;
T.splay(p);
return T.val[p];
}
void add(){
gets(mask);int len=chars.length();
for(int i=0;i<len;i++)ins(chars[i]-'A');
}
}sam;
int main(){
scanf("%d",&Q);sam.build();
while(Q--){
scanf("%s",s);
if(*s=='A')sam.add();
else{
int ans=sam.query();
printf("%d\n",ans);
mask^=ans;
}
}
return 0;
}
SAM动态求 出现至少k次本质不同子串个数:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 25e4+1000;
char s[maxn]; int len,k,n,m; char temp[5];
struct SAM{
int last,cnt,nxt[maxn*2][26],fa[maxn*2],l[maxn*2],num[maxn*2];
int ans;
void init(){
last = cnt=1;
memset(nxt[1],0,sizeof nxt[1]);
fa[1]=l[1]=num[1]=0;
ans=0;
}
int inline newnode(){
cnt++;
memset(nxt[cnt],0,sizeof nxt[cnt]);
fa[cnt]=l[cnt]=num[cnt]=0;
return cnt;
}
void add(int c){
int p = last; int np = newnode();
last = np; l[np] =l[p]+1;
while (p&&!nxt[p][c]){
nxt[p][c] = np;
p = fa[p];
}
if (!p){ fa[np] =1;}
else{
int q = nxt[p][c];
if (l[q]==l[p]+1){fa[np] =q;}
else{
int nq = newnode();
memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
fa[nq] =fa[q]; num[nq] = num[q];
l[nq] = l[p]+1; fa[np] =fa[q] =nq;
while (nxt[p][c]==q){
nxt[p][c]=nq;
p = fa[p];
}
}
}
int temp = last;
while (temp){
if (num[temp]>=k){ break; }
num[temp]++;
if (num[temp]==k){
ans+=l[temp]-l[fa[temp]];
}
temp = fa[temp];
}
}
}sam;
int main(){
while (scanf("%d%d%d",&n,&m,&k)!=EOF){
scanf("%s",s);
len = strlen(s); sam.init();
for (int i=0;i<len;i++){ sam.add(s[i]-'a'); }
while (m--){
int flag;
scanf("%d",&flag);
if (flag==1){
scanf("%s",temp);
sam.add(temp[0]-'a');
}else{
printf("%d\n",sam.ans);
}
}
}
return 0;
}
SAM 字典序第k小串
#include<bits/stdc++.h>
using namespace std;
const int maxn = 9e4+1000;
int len; char s[maxn];
int cntA[maxn]; vector<char> ans;
struct SAM{
int last,cnt,nxt[maxn*2][26],fa[maxn*2],l[maxn*2];
int rk[maxn*2],num[maxn*2];
void init(){
last = cnt=1;
memset(nxt[1],0,sizeof nxt[1]);
fa[1]=l[1] =0;
}
void add(int c){
int p = last; int np = ++cnt;
last = np; l[np] =l[p]+1;
while (p&&!nxt[p][c]){
nxt[p][c] = np;
p = fa[p];
}
if (!p){ fa[np] =1;}
else{
int q = nxt[p][c];
if (l[q]==l[p]+1){ fa[np] =q; }
else{
int nq = ++cnt;
memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
fa[nq] =fa[q]; l[nq] = l[p]+1;
fa[np] =fa[q] =nq;
while (nxt[p][c]==q){
nxt[p][c]=nq;
p = fa[p];
}
}
}
}
void build (){
for (int i=1;i<=cnt;i++){
cntA[l[i]]++;
}
for (int i=1;i<maxn-5;i++){
cntA[i]+=cntA[i-1];
}
for (int i=1;i<=cnt;i++){
rk[cntA[l[i]]--] =i;
}
for (int i=1;i<=cnt;i++){
num[i]=1;
}
for (int i=cnt;i>=1;i--){
int x = rk[i];
for (int i=0;i<26;i++){
if (nxt[x][i]){
num[x]+=num[nxt[x][i]];
}
}
}
num[0]=0;
}
inline void print(){
for (char t:ans){
printf("%c",t);
}
printf("\n");
}
void query(int K){
ans.clear();
int now=1; int sum=0;
while (true){
if (sum==K){
print();
return ;
}
int c=0;
int last =0;
while (sum<K){
sum+=num[nxt[now][c]];
c++;
assert(c<27);
}
c--;
sum-=num[nxt[now][c]];
now = nxt[now][c];
ans.push_back('a'+c);
sum++;
}
}
}sam;
int main(){
int Q;
scanf("%s%d",s,&Q);
sam.init(); int le = strlen(s);
for (int i=0;i<le;i++){
sam.add(s[i]-'a');
}
sam.build();
while (Q--){
int x;
scanf("%d",&x);
sam.query(x);
}
return 0;
}
SA:
SA+Manacher求本质不同回文串个数
#include<bits/stdc++.h>
using namespace std;
#define rank rk
const int MAX = 2e5+10000;
char ch[MAX];
int cntA[MAX],cntB[MAX],A[MAX],B[MAX],tsa[MAX],rank[MAX],SA[MAX],lc[MAX],h[MAX];
int n,t; int Cas =1;
void init(){
memset(ch,0,sizeof ch);
ch[0]='z'+1;
}
void input(){
scanf("%s",ch+1);
n = strlen(ch+1);
ch[n*2+1]='#';
for (int i=n;i>=1;i--){
ch[i*2] = ch[i];
ch[i*2-1] ='#';
}
n = n*2+1;
ch[n+1]='\0';
}
void get_SA(){
for (int i=0;i<=10000;i++) cntA[i]=0;
for (int i=1;i<=n;i++) cntA[ch[i]]++;
for (int i=1;i<=10000;i++) cntA[i]+=cntA[i-1];
for (int i=n;i>=1;i--) SA[cntA[ch[i]]--] =i;
rank[SA[1]]=1;
for (int i=2;i<=n;i++){
rank[SA[i]]=rank[SA[i-1]];
if (ch[SA[i]]!=ch[SA[i-1]]) rank[SA[i]]++;
}
for (int step = 1;rank[SA[n]]<n;step<<=1){
for (int i=0;i<=n;i++)cntA[i]=cntB[i]=0;
for (int i=1;i<=n;i++){
cntA[A[i]=rank[i]]++;
cntB[B[i]=(i+step<=n)?rank[i+step]:0]++;
}
for (int i=1;i<=n;i++) cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];
for (int i=n;i>=1;i--) tsa[cntB[B[i]]--] =i;
for (int i=n;i>=1;i--) SA[cntA[A[tsa[i]]]--] = tsa[i];
rank[SA[1]]=1;
for (int i=2;i<=n;i++){
rank[SA[i]]=rank[SA[i-1]];
if (A[SA[i]]!=A[SA[i-1]]||B[SA[i]]!=B[SA[i-1]]) rank[SA[i]]++;
}
}
}
void get_Height(){
for (int i=1,j=0;i<=n;i++){
if (j) j--;
while (ch[i+j]==ch[SA[rank[i]-1]+j])j++;
h[rank[i]]=j;
}
}
void Manacher(){
lc[1]=1; int k=1;
for (int i=2;i<=n;i++){
int p = k+lc[k]-1;
if (i<=p){
lc[i]=min(lc[2*k-i],p-i+1);
}else{ lc[i]=1; }
while (ch[i+lc[i]]==ch[i-lc[i]])lc[i]++;
if (i+lc[i]>k+lc[k])k=i;
}
}
void print(){
printf("%s\n",ch+1);
for (int i=1;i<=n;i++){
printf("%s %d\n",ch+SA[i],lc[SA[i]]);
}
}
void solve(){
get_SA();get_Height();Manacher();
print();
long long res =0; int cnt=0;
for (int i=2;i<=n;i++){
cnt = min(cnt,h[i]);
res+=max(0,lc[SA[i]]-min(h[i],cnt));
if (lc[SA[i]]>cnt){
cnt = lc[SA[i]];
}
}
printf("Case #%d: %I64d\n",Cas++,res/2);
}
int main(){
scanf("%d",&t);
while (t--){
init();
input();
solve();
}
return 0;
}
PAM
求公共回文串个数。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+100;
struct PAM{
int nxt[maxn][26],len[maxn],cnt[maxn],fail[maxn];
int S[maxn];int last,p,now;
int newnode(int l){
memset(nxt[p],0,sizeof nxt[p]);
cnt[p]=0;len[p]=l;
return p++;
}
void init(){
p =0;
newnode(0);newnode(-1);
last =0;now =0;
S[now++] =-1;fail[0]=1;
}
inline int get_fail(int x){
int tx =x;
while (S[now-len[tx]-2]!=S[now-1]) tx = fail[tx];
return tx;
}
void add(int c){
S[now++] =c;
int cur = get_fail(last);
if (!nxt[cur][c]){
int tt = newnode(len[cur]+2);
fail[tt] = nxt[get_fail(fail[cur])][c];
nxt[cur][c] =tt;
}
last = nxt[cur][c];cnt[last]++;
}
void count(){
for (int i=p-1;i>=0;i--){
cnt[fail[i]]+=cnt[i];
}
cnt[0]=cnt[1]=0;
}
}pam1,pam2;
long long dfs(int u,int v){
long long res =0;
for (int i=0;i<26;i++){
int uu = pam1.nxt[u][i];
int vv = pam2.nxt[v][i];
if (uu&&vv){
res +=1LL*pam1.cnt[uu]*pam2.cnt[vv];
res+=dfs(uu,vv);
}
}
return res;
}
int T;int Cas=1; int len1,len2;
char s1[maxn],s2[maxn];
int main(){
scanf("%d",&T);
while (T--){
pam1.init();pam2.init();
scanf("%s%s",s1,s2);
len1 = strlen(s1);len2 = strlen(s2);
for (int i=0;i<len1;i++){
pam1.add(s1[i]-'a');
}
for (int i=0;i<len2;i++){
pam2.add(s2[i]-'a');
}
pam1.count();pam2.count();
printf("Case #%d: %I64d\n",Cas++,dfs(0,0)+dfs(1,1));
}
return 0;
}
树链剖分
树链剖分+树状数组:
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 250000+100;
struct Seg_Tree{
int sm[MAXN<<1];
inline int lowbit(int _x){return _x&(-_x);}
void build (int l,int r){
for (int i=l;i<=r;i++){
add(i,1);
}
}
void add(int x,int val){
while (x<=MAXN){
sm[x]+=val;
x+=lowbit(x);
}
}
int sum(int x){
int res =0;
while (x){
res+=sm[x];
x-=lowbit(x);
}
return res;
}
int query_sum(int l,int r){
return sum(r)-sum(l-1);
}
}tree;
int first[MAXN*2];int nxt[MAXN*2];int des[MAXN*2];
int tpos[MAXN];int deep[MAXN];int top[MAXN];
int fa[MAXN]; int wson[MAXN]; int size[MAXN];
int n,q,tot=0,cnt=0; char s[10];
inline void add(int _u,int _v){
des[++tot] = _v;
nxt[tot] = first[_u];
first[_u] = tot;
}
void input(){
scanf("%d",&n);
for (int i=1;i<n;i++){
int u,v; scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
}
void dfs(int node,int father){
deep[node] = deep[father]+1;
fa[node] = father; size[node] =1;
for (int t = first[node];t;t = nxt[t]){
int v = des[t];
if (v==father){ continue; }
dfs(v,node);
if (size[v]>size[wson[node]]){