代码很简单的模板就不收录了。

DFT 离散傅立叶变换

pdd curv[262144];
void dft(pdd *a,int l,bool r){
int i,j=l/2,k;
for(i=1;i<l;++i){
if(i<j) swap(a[i],a[j]);
for(k=l/2;j&k;k>>=1) j^=k;
j^=k;
}
for(i=1;(1<<i)<=l;++i){
int cl=(1<<i);
pdd w=mpr(cos(2.0*pi/(double)cl),sin(2.0*pi/(double)cl));
if(r) w.second=-w.second;
for(j=0;j<l;j+=cl){
pdd cur=mpr(1.0,0.0);
for(k=0;k<(cl>>1);++k){
pdd v1=a[j+k],v2=a[j+k+(cl>>1)]*cur;
a[j+k]=v1+v2;
a[j+k+(cl>>1)]=v1-v2;
if(!j) curv[k]=cur*w;
cur=curv[k];
}
}
}
}

hint: 参数 bool r 表示是否在进行逆向的 DFT(即是否是在插值)

hint2: pdd 是手写的 complex 类

NTT 快速数论变换

const LL MOD=998244353,G=3;
const LL MOD2=1004535809,G2=3;
const LL MOD3=65537,G3=3;
int curv[262144];
void ntt(int *a,int l,bool r){
int i,j=l/2,k;
for(i=1;i<l;++i){
if(i<j) swap(a[i],a[j]);
for(k=l/2;j&k;k>>=1) j^=k;
j^=k;
}
for(i=1;(1<<i)<=l;++i){
int cl=(1<<i);
int w=powM(G,(MOD-1)/cl);
if(r) w=powM(w,MOD-2);
for(j=0;j<l;j+=cl){
int cur=1,T=(cl>>1)+j;
for(k=0;k<(cl>>1);++k){
int v1=a[j+k],v2=(LL)a[T+k]*(LL)cur%MOD;
a[j+k]+=v2;
if(a[j+k]>=MOD) a[j+k]-=MOD;
a[T+k]=v1-v2;
if(a[T+k]<0) a[T+k]+=MOD;
if(!j) curv[k]=(LL)cur*w%MOD;
cur=curv[k];
}
}
}
}

hint: powM(A,B)=\(A^B \bmod MOD\)

hint2: 这个DFT板子单次变换耗时约为NTT单次变换耗时的3/2

多项式求逆

注意:该模板及以下所有多项式模板中,参数\(n\)均指\(deg+1\)而非\(deg\)。

int A[262144],B[262144];
void polyinv(int *p,int *f,int n){
int i,j,k,tl=2,llen=0;
while(tl<n) tl<<=1;
memset(f,0,sizeof(int)*tl);
f[0]=powM(p[0]);
for(i=1;i<tl;i<<=1){
int ni=(i<<1);
memset(A,0,sizeof(int)*(ni<<1));
memset(B,0,sizeof(int)*(ni<<1));
for(j=0;j<ni && j<n;++j) A[j]=p[j];
for(j=0;j<i;++j) B[j]=f[j];
ntt(A,ni<<1,0);
ntt(B,ni<<1,0);
for(j=0;j<(ni<<1);++j){
f[j]=B[j]+B[j]-(LL)B[j]*(LL)B[j]%MOD*(LL)A[j]%MOD;
if(f[j]>=MOD) f[j]-=MOD;
if(f[j]<0) f[j]+=MOD;
}
ntt(f,ni<<1,1);
int iv=powM(ni<<1);
for(j=0;j<ni;++j) f[j]=(LL)f[j]*(LL)iv%MOD;
llen=(ni<<1);
}
memset(f+n,0,sizeof(int)*(llen-n));
}

hint: 数组大小应开到4n(其中n为模数中x的次数),这是中间结果的最大次数。

hint2: 传入的p和f必须是不同的数组

多项式ln

int tmp[524288];
void polyln(int *p,int *f,int n){
int i,j,k,len=4;
while(len<=n*2) len<<=1;
memset(f,0,sizeof(int)*len);
for(i=1;i<n;++i){
f[i-1]=(LL)i*(LL)p[i]%MOD;
}
polyinv(p,tmp,n);
ntt(f,len,0);
ntt(tmp,len,0);
for(i=0;i<len;++i){
f[i]=(LL)f[i]*(LL)tmp[i]%MOD;
}
ntt(f,len,1);
for(i=n-1;i>0;--i){
f[i]=(LL)f[i-1]*(LL)powM((LL)i*(LL)len%MOD)%MOD;
}
f[0]=0;
memset(f+n,0,sizeof(int)*(len-n));
}

hint: 数组大小应开到4n(其中n为模数中x的次数),这是中间结果的最大次数。

hint2: 传入的p和f必须是不同的数组

hint3: 传入的多项式p的常数项必须=1

多项式exp

int tmpA[524288],tmpB[524288];
void polyexp_solve(int *p,int *f,int l,int r){
if(l==r) return;
int M=(l+r)/2,i;
polyexp_solve(p,f,l,M);
int len=2;
while(len<(r-l+1)*2) len<<=1;
memset(tmpA,0,sizeof(int)*len);
for(i=l;i<=M;++i){
tmpA[i-l]=f[i];
}
ntt(tmpA,len,0);
memset(tmpB,0,sizeof(int)*len);
for(i=l;i<=r;++i){
tmpB[i-l]=p[i-l];
}
ntt(tmpB,len,0);
for(i=0;i<len;++i){
tmpB[i]=(LL)tmpA[i]*(LL)tmpB[i]%MOD;
}
ntt(tmpB,len,1);
for(i=M;i<r;++i){
f[i+1]+=(LL)tmpB[i-l]*(LL)powM((LL)(i+1)*(LL)len%MOD)%MOD;
if(f[i+1]>=MOD) f[i+1]-=MOD;
}
polyexp_solve(p,f,M+1,r);
}
void polyexp(int *p,int *f,int n){
int i,j,k;
for(i=1;i<n;++i){
p[i-1]=(LL)p[i]*(LL)i%MOD;
}
p[n-1]=0;
memset(f,0,sizeof(int)*n);
f[0]=1;
polyexp_solve(p,f,0,n-1);
}

hint: 数组大小应开到4n(其中n为模数中x的次数),这是中间结果的最大次数。

hint2: 传入的p和f必须是不同的数组

hint3: 传入的多项式p的常数项必须=0

多项式开平方

int tA[524288],tB[524288];
void polysqrt(int *p,int *f,int n){
int i,j,k,tl=2,llen=0;
while(tl<n) tl<<=1;
memset(f,0,sizeof(int)*tl);
f[0]=1;
for(i=1;i<tl;i<<=1){
int ni=(i<<1);
memset(tA,0,sizeof(int)*(ni<<1));
memset(tB,0,sizeof(int)*(ni<<1));
for(j=0;j<ni && j<n;++j) tA[j]=p[j];
polyinv(f,tB,ni);
ntt(tA,ni<<1,0);
ntt(tB,ni<<1,0);
for(j=0;j<(ni<<1);++j){
tB[j]=(LL)tB[j]*(LL)tA[j]%MOD;
}
ntt(tB,ni<<1,1);
int iv=powM(ni<<1),inv2=(MOD+1)/2;
for(j=0;j<ni;++j){
f[j]+=(LL)tB[j]*(LL)iv%MOD;
f[j]=(LL)f[j]*(LL)inv2%MOD;
}
llen=(ni<<1);
}
memset(f+n,0,sizeof(int)*(llen-n));
}

hint: 数组大小应开到4n(其中n为模数中x的次数),这是中间结果的最大次数。

hint2: 传入的p和f必须是不同的数组

hint3: 传入的多项式p的常数项必须=1

后缀自动机与广义后缀自动机

不同于某些无脑写法,这里的GSAM保证不存在等价结点。

struct node{
node *nx[ALPHABET],*fa;
int mxl;
void init(){
mxl=0;
fa=0;
memset(nx,0,sizeof(nx));
}
}*last,*root;
void extend(int v){// for SAM
node *p=last,*np=new node;
np->init();
np->mxl=p->mxl+1;
for(;p && !p->nx[v];p=p->fa) p->nx[v]=np;
if(!p) np->fa=root;
else{
node *q=p->nx[v];
if(q->mxl==p->mxl+1){
np->fa=q;
}
else{
node *nq=new node;
nq->init();
nq->mxl=p->mxl+1;
memcpy(nq->nx,q->nx,sizeof(q->nx));
nq->fa=q->fa;
q->fa=np->fa=nq;
for(;p && p->nx[v]==q;p=p->fa) p->nx[v]=nq;
}
}
last=np;
}
void extend(int c){// for GSAM
node *p=last;
if(p->nx[c]){
if(p->nx[c]->mxl==p->mxl+1)
last=p->nx[c];
else{
node *q=p->nx[c],*nq=new node;
nq->init();
memcpy(nq->nx,q->nx,sizeof(q->nx));
nq->mxl=p->mxl+1;
nq->fa=q->fa;
q->fa=nq;
last=nq;
for(;p && p->nx[c]==q;p=p->fa)
p->nx[c]=nq;
}
return;
}
node *np=new node;
np->init();
np->mxl=p->mxl+1;
for(;p && !(p->nx[c]);p=p->fa)
p->nx[c]=np;
if(!p)
np->fa=root;
else{
node *q=p->nx[c];
if(q->mxl==p->mxl+1)
np->fa=q;
else{
node *nq=new node;
nq->init();
nq->mxl=p->mxl+1;
memcpy(nq->nx,q->nx,sizeof(q->nx));
nq->fa=q->fa;
q->fa=np->fa=nq;
for(;p && p->nx[c]==q;p=p->fa)
p->nx[c]=nq;
}
}
last=np;
}

SA&LCP 后缀数组全家桶

void bsort(){
int i;
memset(cnt,0,sizeof(cnt));
for(i=0;i<n;++i) ++cnt[vy[i]];
for(i=1;i<=n+3 || i<=30;++i) cnt[i]+=cnt[i-1];
for(i=n-1;i>=0;--i) tmp[--cnt[vy[i]]]=i;
memset(cnt,0,sizeof(cnt));
for(i=0;i<n;++i) ++cnt[rk[tmp[i]]];
for(i=1;i<=n+3 || i<=30;++i) cnt[i]+=cnt[i-1];
for(i=n-1;i>=0;--i) ls[--cnt[rk[tmp[i]]]]=tmp[i];
memset(tmp,0,sizeof(tmp));
}
void getsa(){
int i,j,cv;
memset(rk,0,sizeof(rk));
memset(vy,0,sizeof(vy));
for(i=0;i<n;++i) {
rk[i]=s[i]-'a'+1;
}
for(i=2;i<=n*2;i<<=1){
for(j=0;j<n;++j){
vy[j]=rk[j+(i>>1)];
}
bsort();
cv=1;
for(j=0;j<n;++j){
if(j && (rk[ls[j-1]]!=rk[ls[j]]||vy[ls[j-1]]!=vy[ls[j]]))
++cv;
tmp[ls[j]]=cv;
}
memcpy(rk,tmp,sizeof(tmp));
}
}
void getlcp(){
int i,j,lv=0;
for(i=0;i<n;++i){
if(rk[i]==1) continue;
int la=ls[rk[i]-2];
for(j=MAX(0,lv-2);la+j<n&&i+j<n;++j){
if(s[la+j]!=s[i+j]) break;
}
lcp[i]=lv=j;
}
}

hint: vy=value_Y 意为第二排序准则

hint2: rk=rank lv=last_value ls=list

hint3: 可能是因为我的写法太鬼畜了,这段代码里改动几乎任何一处看似无关紧要的细节都会GG……别问我为什么

点分治

void getcen(int ver,int fa,int ts){
int i,j,k,cv=ts-sz[ver];
for(i=0;i<(int)adj[ver].size();++i){
if(adj[ver][i]!=fa && !del[adj[ver][i]]){
UMAX(cv,sz[adj[ver][i]]);
getcen(adj[ver][i],ver,ts);
}
}
UMIN(cur,mpr(cv,ver));
}
void deepin(int ver,int fa){
int i,j,k;
sz[ver]=1;
for(i=0;i<(int)adj[ver].size();++i){
if(!del[adj[ver][i]] && adj[ver][i]!=fa){
deepin(adj[ver][i],ver);
sz[ver]+=sz[adj[ver][i]];
}
}
}
int centroid(int ver){
cur=mpr(iinf,-1);
getcen(ver,-1,sz[ver]);
return cur.second;
}
void solve(int ver){
del[ver]=1;
int i,j,k;
for(i=0;i<(int)adj[ver].size();++i){
if(!del[adj[ver][i]]){
deepin(adj[ver][i],ver);
}
}
for(i=0;i<(int)adj[ver].size();++i){
if(!del[adj[ver][i]]){
solve(centroid(adj[ver][i]));
}
}
}
solve(0);

hint: cv=current_value sz=size

线性基

struct basis{
int arr[35],got[35];
void init(){
memset(arr,0,sizeof(arr));
memset(got,0,sizeof(got));
}
void insert(int v){
int i,j;
for(i=0;i<31;++i){
if(v&(1<<i)) got[i]=1;
}
for(i=30;i>=0;--i){
if(v&(1<<i)){
if(arr[i])
v^=arr[i];
else{
for(j=i-1;j>=0;--j) if(v&(1<<j)) v^=arr[j];
for(j=i+1;j<31;++j) if(arr[j]&(1<<i)) arr[j]^=v;
arr[i]=v;
}
}
}
}
};

线段树合并与分裂

#define SZ(X) ((X)?((X)->cnt):0)
struct node{
node *lc,*rc;
int cnt;
void init(){lc=rc=0;cnt=0;}
void upd(){cnt=SZ(lc)+SZ(rc);}
bool leaf(){return (!lc && !rc);} void ins(int d,int l=0,int r=U){
++cnt;
if(l==r) return;
int M=((l+r)>>1);
if(d<=M){
if(!lc){
lc=new node;
lc->init();
}
lc->ins(d,l,M);
}
else{
if(!rc){
rc=new node;
rc->init();
}
rc->ins(d,M+1,r);
}
}
int loc(int id,int l=0,int r=U){
if(l==r) return l;
int M=((l+r)>>1);
if(id<SZ(lc)) return lc->loc(id,l,M);
return rc->loc(id-SZ(lc),M+1,r);
}
};
node *merge(node *A,node *B){
if(!A || !B) return (A?A:B);
if(A->leaf() && B->leaf()){
A->cnt+=B->cnt;
delete B;
return A;
}
node *lc=merge(A->lc,B->lc),*rc=merge(A->rc,B->rc);
A->lc=lc;
A->rc=rc;
A->cnt=SZ(lc)+SZ(rc);
delete B;
return A;
}
void split(node *S,int sz,node *&A,node *&B){
if(!S) A=B=0;
else if(S->leaf()){
A=S;
B=new node;
B->init();
B->cnt=S->cnt-sz;
// valuation for B->cnt must be before A->cnt, as A==S is possible.
A->cnt=sz;
}
else if(SZ(S->lc)<sz){
A=S;
B=new node;
B->init();
split(A->rc,sz-SZ(S->lc),A->rc,B->rc);
A->upd();B->upd();
}
else{
B=S;
A=new node;
A->init();
split(B->lc,sz,A->lc,B->lc);
A->upd();B->upd();
}
}

网络流退流(Ford-Fulkerson版本)

namespace flows{
const int S=202,T=203;
vector < pii > adj[205];
int id[205][205],flow;
bool vis[205];
void init(){
memset(id,-1,sizeof(id));
int i;
for(i=0;i<205;++i) adj[i].clear();
flow=0;
}
void addedge(int u,int v,int f){
id[u][v]=(int)adj[u].size();
adj[u].push_back(mpr(v,f));
id[v][u]=(int)adj[v].size();
adj[v].push_back(mpr(u,0));
}
int dfs(int ver,int cur,int tar=T){
int i,j,k;
if(ver==tar || !cur) return cur;
vis[ver]=1;
for(i=0;i<(int)adj[ver].size();++i){
pii &E=adj[ver][i];
if(E.second && !vis[E.first]){
int R=id[E.first][ver],
F=dfs(E.first,MIN(cur,E.second),tar);
if(F){
E.second-=F;
adj[E.first][R].second+=F;
return F;
}
}
}
return 0;
}
void set(){
memset(vis,0,sizeof(vis));
}
void push(){
while(1){
set();
int F=dfs(S,iinf);
if(F) flow+=F; else break;
}
}
void edit(int u,int v,int w){
int d=id[u][v],rd=id[v][u],
f=adj[u][d].second+adj[v][rd].second;
if(adj[v][rd].second<=w){
adj[u][d].second+=w-f;
}
else{
int pf=adj[v][rd].second;
adj[u][d].second=adj[v][rd].second=0;
while(pf>w){
set();
int dlt=dfs(u,pf-w,v);
pf-=dlt;
if(!dlt) break;
}
set();
dfs(T,pf-w,v);
set();
dfs(u,pf-w,S);
flow-=pf-w;
adj[v][rd].second=w;
}
}
};

LCT基本款

(之后我大概会在新文章里写一下维护子树信息的LCT?)咕咕咕

namespace LCT{
struct node{
node *s[2],*fa;
int sz,pfa,rev;
void init(){
s[0]=s[1]=fa=0;
pfa=-1;
rev=0;
sz=1;
}
int pos(){
return fa->s[1]==this;
}
void push(){
if(rev){
swap(s[0],s[1]);
if(s[0]) s[0]->rev^=1;
if(s[1]) s[1]->rev^=1;
rev=0;
}
}
void pull(){
sz=SZ(s[0])+SZ(s[1])+1;
}
void rotate(){
if(fa){
node *F=fa;
int ps=pos();
fa=F->fa;
if(fa) fa->s[F->pos()]=this;
pfa=F->pfa;
F->pfa=-1;
F->fa=this;
if(ps){
F->s[1]=s[0];
if(s[0]) s[0]->fa=F;
s[0]=F;
}
else{
F->s[0]=s[1];
if(s[1]) s[1]->fa=F;
s[1]=F;
}
F->pull();
pull();
}
}
void splay(node *tar=0){
while(fa!=tar){
if(fa->fa) fa->fa->push();
fa->push();
push(); if(fa->fa==tar){
rotate();
}
else if(pos()==fa->pos()){
fa->rotate();rotate();
}
else{
rotate();rotate();
}
}
}
}*vers[200005];
void init(){
int i;
for(i=0;i<=n;++i){
vers[i]=new node;
vers[i]->init();
}
}
void expose(int u){
vers[u]->splay();
vers[u]->push();
if(vers[u]->s[1]){
vers[u]->s[1]->pfa=u;
vers[u]->s[1]->fa=0;
vers[u]->s[1]=0;
vers[u]->pull();
}
}
bool extend(int u){
vers[u]->splay();
int &v=vers[u]->pfa;
if(v!=-1){
expose(v);
vers[v]->s[1]=vers[u];
vers[u]->fa=vers[v];
vers[v]->pull();
v=-1;
return 1;
}
return 0;
}
void access(int u){
expose(u);
while(extend(u));
}
void setroot(int u){
access(u);
vers[u]->rev^=1;
}
void link(int u,int v){
setroot(u);
vers[u]->pfa=v;
}
void cut(int u,int v){
setroot(u);
access(v);
vers[v]->push();
vers[v]->s[0]->fa=0;
vers[v]->s[0]=0;
vers[v]->pull();
}
};

可持久化Treap

\(mn\),\(mx\),和\(k\)是节点内维护的一些数据,与模板无关。

#define SZ(x) ((x)?((x)->sz):0)
struct node{
node *s[2];
int mn,mx,sz,k,fix;
void init(int K){
sz=1;
fix=rand();
k=mn=mx=K;
s[0]=s[1]=0;
}
void pull(){
sz=SZ(s[0])+SZ(s[1])+1;
mn=mx=k;
if(s[0]){
mn=min(mn,s[0]->mn);
mx=max(mx,s[0]->mx);
}
if(s[1]){
mn=min(mn,s[1]->mn);
mx=max(mx,s[1]->mx);
}
}
};
void copy(node *S,node *&T){
if(!S) T=0;
T=new node;
*T=*S;
}
void merge(node *&T,node *A,node *B){
if(!A || !B){
copy((A?A:B),T);
return;
}
if(A->fix<B->fix){
copy(A,T);
merge(T->s[1],A->s[1],B);
}
else{
copy(B,T);
merge(T->s[0],A,B->s[0]);
}
T->pull();
}
void splitkey(int K,node *S,node *&A,node *&B){
if(!S){
A=B=0;
return;
}
if(S->k<K){
copy(S,A);
splitkey(K,S->s[1],A->s[1],B);
A->pull();
}
else{
copy(S,B);
splitkey(K,S->s[0],A,B->s[0]);
B->pull();
}
}

动态直线下凸壳

支持\(\mathrm{O}(\log n)\)插入直线,\(\mathrm{O}(\log n)\)单点查询最大值。

常数中等。正确性应该可靠。

const double MOGIC=-1926.0817,eps=1e-8;
struct Line{
LL K,B;
mutable double T;
void set(LL k,LL b,double t=MOGIC){
K=k;B=b;T=t;
}
bool operator <(Line Y) const{
if(T==MOGIC||Y.T==MOGIC) return (K!=Y.K?K<Y.K:B>Y.B);
return T<Y.T;
}
}tmp;
LL eval(LL d,Line line){
return d*line.K+line.B;
}
double intersect(Line A,Line B){
return (double)(A.B-B.B)/(double)(B.K-A.K);
}
struct convex{
set < Line > lines;
void ins(Line L){
L.T=MOGIC;
if(lines.empty()){
L.T=(double)-linf;
lines.insert(L);
}
else{
set < Line >::iterator it=lines.lower_bound(L),lt=it,cr;
if(it->K==L.K && it->B==L.B) return;
if(it==lines.begin()){
L.T=(double)-linf;
if(it->K==L.K) lines.erase(lines.begin());
if(!lines.empty()){
it=lines.begin();
it->T=intersect(L,*it);
while((++it)!=lines.end() && lines.begin()->T>it->T+eps){
lines.erase(lines.begin());
it->T=intersect(L,*it);
}
}
lines.insert(L);
return;
}
if((--lt)->K==L.K) return;
if(it==lines.end()){
L.T=intersect(L,*(lines.rbegin()));
while(lines.rbegin()->T>L.T-eps){
lt=lines.end();
lines.erase(--lt);
L.T=intersect(L,*(lines.rbegin()));
}
lines.insert(L);
return;
}
while(1){
cr=it++;
if(it==lines.end()) break;
if(intersect(*lt,L)>intersect(*lt,*cr)-eps || intersect(*it,L)<intersect(*it,*cr)-eps)
break;
lines.erase(cr);
}
if(cr->K==L.K){
lines.erase(cr);
while(lt!=lines.begin()){
cr=lt--;
L.T=intersect(*cr,L);
if(L.T<lines.rbegin()->T+eps) lines.erase(cr); else break;
}
L.T=intersect(*lines.rbegin(),L);
lines.insert(L);
return;
}
--it;
while(1){
if(lt==lines.begin()) break;
cr=lt--;
if(intersect(*it,L)<intersect(*it,*cr)+eps || intersect(*lt,L)>intersect(*lt,*cr)+eps){
lt=cr;
break;
}
lines.erase(cr);
}
L.T=intersect(*lt,L);
if(L.T<intersect(*it,L)){
it->T=intersect(*it,L);
lines.insert(L);
}
}
}
LL qry(LL D){
tmp.set(0,0,D);
set < Line > ::iterator it=lines.lower_bound(tmp);
return eval(D,*(--it));
}
};

KM算法

二分图最大权匹配,见UOJ #80

namespace KM{
int n[2],w[505][505];
int matchL[505],matchR[505],pred[505];
int labL[505],labR[505],slk[505];
bool inS[505];
void init(int N){
n[0]=n[1]=N;
memset(w,0,sizeof(w));
memset(matchL,-1,sizeof(matchL));
memset(matchR,-1,sizeof(matchR));
}
LL solve(){
int i,j,k;
memset(labR,0,sizeof(labR));
for(i=0;i<n[0];++i){
labL[i]=0;
for(j=0;j<n[1];++j) UMAX(labL[i],w[i][j]);
}
for(i=0;i<n[0];++i){
if(matchL[i]!=-1) continue;
memset(inS,0,sizeof(inS));
inS[i]=1;
for(j=0;j<n[1];++j){
slk[j]=labL[i]+labR[j]-w[i][j];
}
int dec=0;
while(dec!=-1){
dec=-2;
while(dec==-2){
dec=iinf;
for(j=0;j<n[1];++j){
if(!slk[j]){
for(k=0;k<n[0];++k){
if(inS[k] && w[k][j]==labL[k]+labR[j]) break;
}
pred[j]=k;
slk[j]=-1;
int v=matchR[j];
if(v==-1){
for(k=0;j!=-1;j=k){
k=matchL[pred[j]];
matchR[j]=pred[j];
matchL[pred[j]]=j;
}
dec=-1;
}
else{
inS[v]=1;
for(k=0;k<n[1];++k){
UMIN(slk[k],labL[v]+labR[k]-w[v][k]);
}
dec=-2;
}
break;
}
if(slk[j]>0) UMIN(dec,slk[j]);
}
if(dec>0){
for(j=0;j<n[0];++j){
if(inS[j]) labL[j]-=dec;
}
for(j=0;j<n[1];++j){
if(slk[j]!=-1)
slk[j]-=dec;
else
labR[j]+=dec;
}
}
}
}
}
LL res=0ll;
for(i=0;i<n[0];++i) res+=(LL)w[i][matchL[i]];
return res;
}
};

带花树算法

一般图最大匹配,见UOJ #79

namespace Blossom{
int n,sta[505],fa[505];
int pred[505],match[505];
int tick,mark[505];
int pl,pr,que[1005];
vector < int > adj[505];
void init(int N){
n=N;
int i;
for(i=0;i<n;++i) adj[i].clear();
memset(mark,0,sizeof(mark));
memset(match,-1,sizeof(match));
tick=0;
}
int ancestor(int x){
return (fa[x]==x?x:(fa[x]=ancestor(fa[x])));
}
int lca(int u,int v){
++tick;
while(u==-1 || mark[u]!=tick){
if(u!=-1){
mark[u]=tick;
u=(match[u]==-1?-1:ancestor(pred[match[u]]));
}
swap(u,v);
}
return u;
}
void blossom(int u,int v,int L){
while(ancestor(v)!=L){
pred[v]=u;
u=match[v];
if(sta[u]==2){
sta[u]=1;
que[pr++]=u;
}
fa[u]=fa[v]=L;
v=pred[u];
}
}
int solve(){
int i,j,k,res=0;
for(i=0;i<n;++i){
if(match[i]!=-1) continue;
for(j=0;j<n;++j) fa[j]=j;
memset(sta,0,sizeof(sta));
pl=0;pr=1;
que[0]=i;
sta[i]=1;
while(pl<pr && match[i]==-1){
int v=que[pl++];
for(j=0;j<(int)adj[v].size();++j){
int u=adj[v][j];
if(!sta[u]){
pred[u]=v;
if(match[u]==-1){
int nx=0;
for(k=u;k!=-1;k=nx){
nx=match[pred[k]];
match[k]=pred[k];
match[pred[k]]=k;
}
++res;
break;
}
else{
sta[u]=2;
sta[match[u]]=1;
que[pr++]=match[u];
}
}
else if(sta[u]==1 && ancestor(u)!=ancestor(v)){
int LCA=lca(u,v);
blossom(u,v,LCA);
blossom(v,u,LCA);
}
}
}
}
return res;
}
};

ZKW费用流

来源

namespace ZKW{// min cost max flow
const int V=440, E=V*2, maxint=0x3F3F3F3F;
struct etype{
int t, c, u;
etype *next, *pair;
etype() {}
etype(int T, int C, int U, etype* N): t(T), c(C), u(U), next(N) {}
void* operator new(unsigned long long, void* p){return p;}
}*e[V], Te[E+E], *Pe;
int S, T, n, piS, cost;
bool v[V];
void init(int N){
n=N;S=0;T=1;
Pe=Te;
memset(e,0,sizeof(etype*)*(n+2));
cost=piS=0;
}
void addedge(int s, int t, int c, int u){
e[s] = new(Pe++) etype(t, +c, u, e[s]);
e[t] = new(Pe++) etype(s, -c, 0, e[t]);
e[s]->pair = e[t];
e[t]->pair = e[s];
}
int aug(int no, int m){
if (no == T) return cost += piS * m, m;
v[no] = true;
int l = m;
for (etype *i = e[no]; i; i = i->next)
if (i->u && !i->c && !v[i->t]){
int d = aug(i->t, l < i->u ? l : i->u);
i->u -= d, i->pair->u += d, l -= d;
if (!l) return m;
}
return m - l;
}
bool modlabel(){
static int d[V]; memset(d, 0x3F, sizeof(d)); d[T] = 0;
static deque<int> Q; Q.push_back(T);
while(Q.size()){
int dt, no = Q.front(); Q.pop_front();
for(etype *i = e[no]; i; i = i->next)
if(i->pair->u && (dt = d[no] - i->c) < d[i->t])
(d[i->t] = dt) <= d[Q.size() ? Q.front() : 0]
? Q.push_front(i->t) : Q.push_back(i->t);
}
for(int i = 0; i < n; ++i)
for(etype *j = e[i]; j; j = j->next)
j->c += d[j->t] - d[i];
piS += d[S];
return d[S] < maxint;
}
void getcost(){
while(modlabel())
do memset(v, 0, sizeof(int)*(n+2));
while(aug(S, maxint));
}
}

替罪羊式的K-D Tree

题目链接

在平面上支持插入点、查询曼哈顿最近点。

bool dim;
bool cmp(pii A,pii B){
return (dim?A.SC:A.FS)<(dim?B.SC:B.FS);
}
inline int dis(pii A,pii B){
return ABS(A.FS-B.FS)+ABS(A.SC-B.SC);
}
int ans,cnt;
pii ele[600005];
#define SZ(x) ((x)?((x)->sz):0)
struct node{
node *s[2];
pii cen;
int dep,xl,xr,yl,yr,sz;// coordinates of rectangle
bool bad(){
return MAX(SZ(s[0]),SZ(s[1]))*4>sz*3+20;
}
void init(){
s[0]=s[1]=0;
dep=sz=0;
}
void extend(int d){
s[d]=new node;
s[d]->init();
s[d]->xl=xl;s[d]->xr=xr;
s[d]->yl=yl;s[d]->yr=yr;
s[d]->dep=dep+1;
if(!d){
if(dep&1) s[0]->yr=cen.SC;
else s[0]->xr=cen.FS;
}
else{
if(dep&1) s[1]->yl=cen.SC;
else s[1]->xl=cen.FS;
}
}
void build(pii *L,pii *R){
sz=R-L+1;
int M=sz/2,i,j,k;
dim=(dep&1);
nth_element(L,L+M,R+1,cmp);
cen=*(L+M);
if(M){
extend(0);
s[0]->build(L,L+M-1);
}
if(L+M<R){
extend(1);
s[1]->build(L+M+1,R);
}
}
inline int sdis(int L,int R,int X){
return ((X>=L && X<=R)?0:MIN(ABS(X-L),ABS(X-R)));
}
int rdis(pii P){
return sdis(xl,xr,P.FS)+sdis(yl,yr,P.SC);
}
void query(pii P){
UMIN(ans,dis(P,cen));
if(rdis(P)>=ans) return;
node *A=s[0],*B=s[1];
if(B && (!A || A->rdis(P)>B->rdis(P)))
swap(A,B);
if(A) A->query(P);
if(B) B->query(P);
}
void ins(pii P,node *&ls){
++sz;
dim=(dep&1);
int d=cmp(cen,P);
if(!s[d]){
extend(d);
s[d]->cen=P;
s[d]->sz=1;
ls=0;
}
else s[d]->ins(P,ls);
if(bad()) ls=this;
}
void travel(){
if(s[0]) s[0]->travel();
ele[cnt++]=cen;
if(s[1]) s[1]->travel();
}
void del(){
if(s[0]){
s[0]->del();
delete s[0];
s[0]=0;
}
if(s[1]){
s[1]->del();
delete s[1];
s[1]=0;
}
}
}*root;
void rebuild(node *p){
cnt=0;
p->travel();
p->del();
p->build(ele,ele+cnt-1);
}
void insert(pii P){
node *r=0;
root->ins(P,r);
if(r) rebuild(r);
}
int query(pii P){
ans=iinf;
root->query(P);
return ans;
}

广义圆方树建树

对于点双建立方点。

int en[200005],low[200005],tick,cnt;// initially cnt set to |V|, en set to -1
int sz,stk[200005],fa[400005];
vector < int > son[400005],adj[200005];
void setfa(int s,int f){
fa[s]=f;
son[f].push_back(s);
}
void tarjan(int v,int f){
int i,j,k;
stk[sz++]=v;
en[v]=low[v]=tick++;
for(i=0;i<(int)adj[v].size();++i){
int u=adj[v][i];
if(u!=f){
if(en[u]==-1){
tarjan(u,v);
UMIN(low[v],low[u]);
if(low[u]==en[v]){
int cen=cnt++;
setfa(cen,v);
while(sz && en[stk[sz-1]]>=en[u]){
setfa(stk[sz-1],cen);
--sz;
}
}
else if(low[u]==en[u]){
int cen=cnt++;
setfa(u,cen);
setfa(cen,v);
assert(sz && stk[sz-1]==u);
--sz;
}
}
else UMIN(low[v],en[u]);
}
}
}

支持DecreaseKey的配对堆

struct ph{// min-heap
ph *son,*sib,*fa;
pli key;
void init(pli dat){
key=dat;
son=sib=fa=0;
}
};
ph *merge(ph *A,ph *B){
if(!A || !B) return A?A:B;
A->sib=B->sib=A->fa=B->fa=0;
if(A->key>B->key) swap(A,B);
B->sib=A->son;
if(A->son) A->son->fa=B;
B->fa=A;
A->son=B;
return A;
}
ph *mergesibs(ph *A){
if(!A) return 0;
if(!A->sib){
A->fa=0;
return A;
}
ph *O=A->sib->sib;
if(!O) return merge(A,A->sib);
return merge(merge(A,A->sib),mergesibs(O));
}
ph *deckey(ph *A,ph *tar,LL dlt){
tar->key.FS-=dlt;
ph *F=tar->fa;
if(!F) return A;
ph *S=tar->sib;
(F->son==tar?F->son:(F->sib))=S;
if(S) S->fa=F;
return merge(A,tar);
}
ph *popmin(ph *A){
return mergesibs(A->son);
}

BM算法求解最短线性递推式

int n,a[3005],cnt,fail[3005],dlt[3005];
vector < int > coe[3005];
int delta(vector < int > &coes,int p){
if(p<(int)coes.size()) return 0;
int r=a[p],i;
for(i=0;i<(int)coes.size();++i){
r-=(LL)coes[i]*(LL)a[p-i-1]%MOD;
if(r<0) r+=MOD;
}
return r;
}
vector < int > BM(){// get the shortest recurrence fomula from array a
int i,j,k;
vector < int > cur;
coe[cnt]=cur;
int ptr=0;
int d=-1,v=-1;
while(1){
while(ptr<n){
dlt[cnt]=delta(cur,ptr);
fail[cnt]=ptr;
if(!dlt[cnt])
++ptr;
else break;
}
if(ptr==n) break;
if(!cnt){
cur.resize(fail[cnt]+1,0);
coe[++cnt]=cur;
}
else{
int prt1=fail[cnt]-fail[d]-1,prt3=(int)coe[d].size();
if((int)cur.size()<prt1+prt3+1)
cur.resize(prt1+prt3+1,0);
int mul=(LL)dlt[cnt]*(LL)powM(dlt[d])%MOD;
cur[prt1]+=mul;
cur[prt1]%=MOD;
for(i=0;i<prt3;++i){
int &T=cur[prt1+1+i];
T-=(LL)mul*(LL)coe[d][i]%MOD;
if(T<0) T+=MOD;
}
coe[++cnt]=cur;
}
if(fail[cnt-1]-(int)coe[cnt-1].size()>v){
v=fail[cnt-1]-(int)coe[cnt-1].size();
d=cnt-1;
}
}
return cur;
}

类欧几里得算法

题目链接

LL pws(int n,int k){
if(!k) return (LL)n%MOD;
if(k==1) return (LL)n*(LL)(n+1)/2ll%MOD;
if(k==2) return (LL)n*(LL)(n+1)%MOD*(LL)(2*n+1)%MOD*inv6%MOD;
}
void calc(int a,int b,int c,int n,LL &f,LL &g,LL &h){// a,c,n>=0
if(!a){
int nn=max(0,b/c);
f=(LL)nn*(LL)n%MOD;
g=(LL)nn*pws(n,1)%MOD;
h=pws(nn,1)*(LL)n%MOD;
}
else if(b<0){
int mv=(-b+a-1)/a,nb=b+mv*a;
if(n<=mv)
f=g=h=0ll;
else{
calc(a,nb,c,n-mv,f,g,h);
(g+=f*mv)%=MOD;
}
if(n>=mv){
(f+=(LL)(nb/c))%=MOD;
(g+=(LL)mv*(LL)(nb/c))%=MOD;
(h+=pws(nb/c,1))%=MOD;
}
}
else if(a>=c){
LL da=a/c;
LL df=da*pws(n,1);
LL dg=da*pws(n,2);
LL dh=da*inv2%MOD*pws(n,1)-da*da%MOD*inv2%MOD*pws(n,2);// +da*g reserved
calc(a-c*da,b,c,n,f,g,h);
(f+=df)%=MOD;
(g+=dg)%=MOD;
(h+=dh+g*da)%=MOD;
}
else{
int nn=((LL)a*(LL)n+(LL)b)/(LL)c;
calc(c,-b-1,a,nn,f,g,h);
f=((LL)n*(LL)nn-f)%MOD;
LL ng=(pws(n,1)*(LL)nn-h)%MOD,nh=(pws(nn,1)*(LL)n-g)%MOD;
g=ng;h=nh;
}
}
void answer(int a,int b,int c,int n,LL &f,LL &g,LL &h){
++n;
b-=a;
calc(a,b,c,n,f,g,h);
f=(f+MOD*MOD)%MOD;g=(g+MOD*MOD)%MOD;h=(h+MOD*MOD)%MOD;
h=(h*2ll+MOD-f)%MOD;
g=(g+MOD-f)%MOD;
}

最新文章

  1. 在Intellij IDEA 下通过Maven新建项目的一些体会
  2. HTML5学习之拖放(十)
  3. Linux 面试题总结
  4. Java for LeetCode 173 Binary Search Tree Iterator
  5. codeforces C. Vasily the Bear and Sequence 解题报告
  6. paper 28 :一些常见常用数据库的下载网站集锦
  7. Hibernate 中update hql语句
  8. cocos2d制作动态光晕效果基础——blendFunc
  9. [cocos2dx笔记015]关于cocos2dx Button三种状态说明
  10. SZU:D89 The Settlers of Catan
  11. Vue.js 系列教程 4:Vuex
  12. TypeScript设计模式之备忘录、命令
  13. 为何我会喜欢封闭的apple?
  14. RHEL系统初始化步骤
  15. IDEA Maven项目的Mybatis逆向工程
  16. 當 Alexa 遇上 ESP8266 (一)
  17. centos exfat格式U盘不支持问题
  18. 关于XCode工程中PrefixHead.pch文件的使用
  19. opencv学习之路(15)、形态学其他操作(开、闭、顶帽、黑帽、形态学梯度)
  20. 奇怪吸引子---DequanLi

热门文章

  1. LESS初体验
  2. python中的 if __name__ == “__main__”: 有什么用
  3. Android(java)学习笔记22:我们到底该如何处理异常?
  4. Python语言程序设计基础(5)—— 函数和代码复用
  5. HDU 6178 Monkeys
  6. luogu P3787 冰精冻西瓜
  7. 二.Mybatis 增删改查
  8. maven学习记录二——依赖管理
  9. js 3秒后跳转页面的实现代码
  10. Vue组件通讯黑科技