我要复习所有的模板
二分 gcd
int gcd(int a,int b) {
int az=__builtin_ctz(a), bz=__builtin_ctz(b), z=min(az,bz), dif;
b>>=bz;
while(a) {
a>>=az, dif=b-a;
az=__builtin_ctz(dif);
if(a<b) b=a;
a=dif<0?-dif:dif;
}
return b<<z;
}
异或多重集树哈希
const ull mask=std::chrono::steady_clock::now().time_since_epoch().count();
int ull shift(ull x) {
x^=mask, x^=x<<13, x^=x>>7, x^=x<<17, x^=mask;
return x;
}
void dp(int x,int fa) {
int ms=0; siz[x]=1;
for(int y:to[x]) if(y^fa) dp(y,x), siz[x]+=siz[y], ms=max(ms,siz[y]);
ms=max(ms,n-siz[x]);
if(ms<=n/2) heart.pb(x);
}
void Hash(int x,int fa) {
hsh[x]=1;
for(int y:to[x]) if(y^fa) Hash(y,x), hsh[x]+=shift(hsh[y]);
trees.insert(hsh[x]);
}
heart.clear(), dp(1,0);
for(int rt:heart) {
trees.clear(), Hash(rt,0);
qwq=max(trees,qwq);
质数树哈希
int vis[M], p[M], top;
void init() {
int d=1299709;
up(i,2,d) if(!vis[i]) {
vis[i]=1, p[++top]=i;
up(j,2,d/i) vis[i*j]=1;
}
}
struct Tree {
int n, siz[N]; ull hsh[N]; vector<int> to[N];
void build(int x) { n=x; }
void eadd(int u,int v) { to[u].pb(v), to[v].pb(u); }
void Hash(int x,int fa) {
hsh[x]=1, siz[x]=1;
for(int y:to[x]) if(y^fa) Hash(y,x), siz[x]+=siz[y], hsh[x]+=hsh[y]*p[siz[y]];
}
void change(int x,int fa,int I) {
if(fa) hsh[x]=hsh[x]+p[n-siz[x]]*(hsh[fa]-hsh[x]*p[siz[x]]);
for(int y:to[x]) if(y^fa) change(y,x,I);
}
};
拓展欧几里得
我们要求一组 \(ax+by=c\) 的解 \((x,y)\),首先充要条件是 \(\gcd(x,y)|c\),于是我们先在做欧几里得的时候求解一组 \(ax+by=\gcd(a,b)\) 再简单乘即可。
int exgcd(int a,int b,int &x,int &y) {
if(b==0) { x=1, y=0; return a; }
int d=exgcd(b,a%b,x,y);
int t=x; x=y, y=t-a/b*y;
return d;
}
lnk,括欧还可以在模意义下部分还原分数,具体见 P10383。
设 \(g=\text{lcm}(a,b)\),求出一组特解 \(ax_0+by_0=c\),那么一元二次的通解形式是 \(a(x_0+\frac{g}{b}k)+b(y_0-\frac{g}{a}k)=c\)
线性筛素数
埃氏筛一个合数被标记次数没有严格保证,我们考虑让一个合数只被标记一次,贡献方式为「\(最小质因子\times 常数\)」,那么一个常数要去成所有不超过其最小质因子的素数去贡献。
int n, q, p[M], top; bool vis[N];
up(i,2,n) {
if(!vis[i]) p[++top]=i;
for(int j=1; j<=top&&i*p[j]<=n; ++j) {
int x=i*p[j]; vis[x]=1;
if(i%p[j]==0) break;
}
}
在素数的位置带 \(\log\) 总的复杂度仍然是 \(O(n)\),因为质数的幂总共只有 \(\frac{n}{\log n}\) 那么多。
欧拉筛线性递推 欧拉/莫比乌斯 函数
分别照着定义式递推即可,代码包含在杜教筛那里 qwq
杜教筛
具体过程如 lnk,因为年代并不久远不再赘述。
数论函数求前缀和可以套杜教筛公式,计算 \(S(n)=\sum_{i=1}^n f(i)\),不妨构造 \(h(i)=\sum_{d|i}f(d)g(\frac{n}{d})\),然后套用公式 \(g(1)S(n)=\sum_{i=1}^n h(i)-\sum_{i=2}^n g(i)S(\lfloor\frac{n}{i}\rfloor)\),整除分块+记忆化复杂度 \(O(n^{\frac{3}{4}})\),加上到 \(n^{\frac{2}{3}}\) 的预处理可以做到 \(O(n^{\frac{2}{3}})\)。
思想大概是什么考虑构造卷积,然后考虑 \(f\) 对 \(g\) 的贡献发现是前缀和的形式,欧拉函数和莫比乌斯函数用 \(n=\sum_{d|n}\phi(d),[n=1]=\sum_{d|n}\mu(d)\) 来做(
int t, n, k=5e6;
int vis[N], p[N], top, phi[N], mu[N];
map<int,int> sphi, smu;
void init() {
vis[0]=vis[1]=phi[1]=mu[1]=1;
up(i,2,k) {
if(!vis[i]) p[++top]=i, phi[i]=i-1, mu[i]=-1;
for(int j=1; j<=top&&i*p[j]<=k; ++j) {
int x=i*p[j]; vis[x]=1;
if(i%p[j]) mu[x]=-mu[i], phi[x]=phi[i]*(p[j]-1);
else { mu[x]=0, phi[x]=phi[i]*p[j]; break; }
}
}
up(i,1,k) phi[i]+=phi[i-1], mu[i]+=mu[i-1];
}
int getphi(int x) {
if(x<=k) return phi[x];
if(sphi.find(x)!=sphi.end()) return sphi[x];
int res=(1+x)*x/2;
for(int l=2, r; l<=x; l=r+1) {
r=min(x,x/(x/l));
res-=(r-l+1)*getphi(x/l);
}
return sphi[x]=res;
}
int getmu(int x) {
if(x<=k) return mu[x];
if(smu.find(x)!=smu.end()) return smu[x];
int res=1;
for(int l=2, r; l<=x; l=r+1) {
r=min(x,x/(x/l));
res-=(r-l+1)*getmu(x/l);
}
return smu[x]=res;
}
康托展开
考虑比 \(a\) 小的排列数,枚举 \(1,\dots,i-1\) 位相同,那么 \(a'_i<a_i\),从后面拉一个上来,然后剩下的可以随便排列。
差分约束
考虑一堆方程组形如 \(x_i+d\geq x_j\),不妨写成 \(i\to j:d\) 去跑最短路,无解就是存在负环(有点 \(入队次数>n\))。
注意最短路去跑具有极大性,就是说每一个 \(x\) 其实都尽量往极值去取了,天生极端化了字典序。
dfs spfa 判负环
负环从某个位置开始走可以一直都是负的,我们可以用这个来优化常数,有些题目(比如 P3199)下这样判断跑的飞快。
int spfa(int x) {
vis[x]=1;
for(pii p:to[x]) {
int y=p.first; db val=p.second;
if(dis[x]+val<dis[y]) {
dis[y]=dis[x]+val;
if(vis[y]||spfa(y)) return 1;
}
}
vis[x]=0;
return 0;
}
bool check() {
up(i,1,n) dis[i]=vis[i]=0;
up(i,1,n) if(spfa(i)) return 1;
return 0;
}
无向图 割边/割点 判定法则
考虑随便搜出一个 dfs 树,一个 边/点 是不是割就看有没有跨越的东西就行了,为了方便,不妨令 \(dfn/low\) 表示 时间戳/能回溯的最小时间戳,这样只用比大小就能判断了,注意割边要判重。
一条边 \((x,y)\) 在 \(low[y]>dfn[x]\) 是为割边,一个点在有儿子 \(y\) 使得 \(low[y]\geq dfn[x]\) 时是割点,但是注意特判根,根的判定是具有多个儿子。
边双联通分量
去掉割边然后算联通即可,然后重新建图是简单东西。
#define num(x) ((x+1)>>1)
int n, m, tot, dfn[N], low[N], stamp, cut[M], gp[N], cnt;
vector<pair<int,int> > to[N];
void tarjan(int x,int lnk) {
dfn[x]=low[x]=++stamp;
for(pii p:to[x]) {
int y=p.first, i=p.second;
if(num(i)==num(lnk)) continue;
if(dfn[y]) low[x]=min(low[x],dfn[y]);
else {
tarjan(y,i), low[x]=min(low[x],low[y]);
if(low[y]>dfn[x]) cut[num(i)]=1;
}
}
}
void dfs(int x) {
for(pii p:to[x]) {
int y=p.first, i=p.second;
if(cut[num(i)]||gp[y]) continue;
gp[y]=cnt, dfs(y);
}
}
cin >> n >> m;
up(i,1,m) {
int u, v;
cin >> u >> v;
to[u].pb(mp(v,++tot));
to[v].pb(mp(u,++tot));
}
up(i,1,n) if(!dfn[i]) tarjan(i,0);
up(i,1,n) if(!gp[i]) gp[i]=++cnt, dfs(i);
点双联通分量、广义圆方树
首先点双在搜索栈里面考虑就行了,建图可以使用广义圆方树,就是对于每一个点双建立一个方点,然后向所在的分量的圆点连边,这样子可以保证性质不变,注意方点要开两倍空间,重边要特判。
int n, m, dfn[N], low[N], tot, stamp, stk[N], top;
vector<int> F[N], G[N<<1];
void tarjan(int x) {
dfn[x]=low[x]=++stamp, stk[++top]=x;
for(int y:F[x]) {
if(dfn[y]) low[x]=min(low[x],dfn[y]);
else {
tarjan(y), low[x]=min(low[x],low[y]);
if(low[y]>=dfn[x]) {
++tot; int p;
while(stk[top+1]!=y) {
p=stk[top--];
G[p].pb(tot), G[tot].pb(p);
}
G[tot].pb(x), G[x].pb(tot);
}
}
}
}
cin >> n >> m, tot=n;
up(i,1,m) {
int u, v; cin >> u >> v;
if(u!=v) F[u].pb(v), F[v].pb(u);
}
up(i,1,n) if(!dfn[i]) tarjan(i);
强联通分量
其实可以不写 tarjan,正图做一次 dfs 记录回溯时间压入栈,按照回溯时间大到小在反图上搜出强联通分量,应该很好理解。
int n, m, stk[N], top, gp[N], cnt, vis[N], p;
vector<int> F[N], G[N];
void dfs(int x) {
vis[x]=1;
for(int y:F[x]) if(!vis[y]) dfs(y);
stk[++top]=x;
}
void stain(int x) {
for(int y:G[x]) if(!gp[y]) gp[y]=cnt, stain(y);
}
cin >> n >> m;
up(i,1,m) {
int u, v; cin >> u >> v;
F[u].pb(v), G[v].pb(u);
}
up(i,1,n) if(!vis[i]) dfs(i);
dn(i,n,1) if(!gp[p=stk[i]]) gp[p]=++cnt, stain(p);
网络最大流
建出反边,每次找出增广路流,是一个分层图最短路。
注意有些题目需要 \(\infty\) 的连边,但是不能给初始流量的 \(\infty\uparrow\) 不然会不够流。
int n, m, s, t, dis[N], maxflow, cur[N];
int hd[N], nxt[M], eg[M], to[M], tot=1, fl;
queue<int> q;
void eadd(int u,int v,int w) {
to[++tot]=v, eg[tot]=w;
nxt[tot]=hd[u], hd[u]=tot;
}
bool bfs() {
up(i,1,n) dis[i]=0;
while(q.size()) q.pop();
dis[s]=1, q.push(s);
while(q.size()) {
int x=q.front(); q.pop();
for(int i=hd[x]; i; i=nxt[i]) {
int y=to[i], w=eg[i];
if(w&&!dis[y]) dis[y]=dis[x]+1, q.push(y);
}
}
return dis[t];
}
int dfs(int x,int sum) {
if(x==t) return sum;
int res=0;
for(int i=cur[x]; i&∑ i=nxt[i]) {
cur[x]=i;
int y=to[i], w=eg[i];
if(w&&dis[x]+1==dis[y]) {
int k=dfs(y,min(sum,w));
if(!k) dis[y]=0;
eg[i]-=k, eg[i^1]+=k, res+=k, sum-=k;
}
}
return res;
}
int getflow() {
while(bfs()) {
up(i,1,n) cur[i]=hd[i];
maxflow+=dfs(s,inf);
}
return maxflow;
}
费用流
int n, m, s, t, dis[N], in[N], maxflow, mincost;
int hd[N], nxt[M], eg[M], to[M], lv[M], tot=1, cur[N];
queue<int> q;
inline void fadd(int u,int v,int w,int l) { to[++tot]=v, eg[tot]=w, lv[tot]=l, nxt[tot]=hd[u], hd[u]=tot; }
void eadd(int u,int v,int w,int l) { fadd(u,v,w,l), fadd(v,u,0,-l); }
int spfa() {
int flag=0;
up(i,1,n) dis[i]=inf;
dis[s]=0, q.push(s), in[s]=1;
while(q.size()) {
int x=q.front(); q.pop();
flag|=(x==t), in[x]=0;
for(int i=hd[x]; i; i=nxt[i]) {
int y=to[i], w=eg[i], v=lv[i];
if(w&&dis[x]+v<dis[y]) {
dis[y]=dis[x]+v;
if(!in[y]) in[y]=1, q.push(y);
}
}
}
return flag;
}
int dfs(int x,int sum) {
if(x==t) return sum;
in[x]=1; int res=0;
for(int i=cur[x]; i&∑ i=nxt[i]) {
cur[x]=i;
int y=to[i], w=eg[i], v=lv[i];
if(!in[y]&&w&&dis[x]+v==dis[y]) {
int k=dfs(y,min(sum,w));
if(k) eg[i]-=k, eg[i^1]+=k, res+=k, sum-=k, mincost+=k*v;
}
}
in[x]=0;
return res;
}
int getflow() {
while(spfa()) {
up(i,1,n) cur[i]=hd[i];
maxflow+=dfs(s,inf);
}
}
FFT
#include<bits/stdc++.h>
#define db double
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const db pi=acos(-1);
const int N=2145141;
int n, m, tr[N];
struct cp { db x, y; } f[N], g[N], sav[N];
typedef const cp ccp;
cp operator+(ccp &a,ccp &b) { return (cp){a.x+b.x,a.y+b.y}; }
cp operator-(ccp &a,ccp &b) { return (cp){a.x-b.x,a.y-b.y}; }
cp operator*(ccp &a,ccp &b) { return (cp){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x}; }
void fft(cp *f,bool op) {
up(i,0,n-1) if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int p=2; p<=n; p<<=1) {
int len=p>>1;
cp tG=(cp){cos(2*pi/p),sin(2*pi/p)};
if(!op) tG.y*=-1;
for(int k=0; k<n; k+=p) {
cp buf=(cp){1,0};
up(l,k,k+len-1) {
cp tt=buf*f[len+l];
f[len+l]=f[l]-tt, f[l]=f[l]+tt;
buf=buf*tG;
}
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
up(i,0,n) cin >> f[i].x;
up(i,0,m) cin >> g[i].x;
for(m+=n, n=1; n<=m; n<<=1);
up(i,0,n-1) tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
fft(f,1), fft(g,1);
up(i,0,n-1) f[i]=f[i]*g[i];
fft(f,0);
up(i,0,m) cout << (int)(f[i].x/n+0.49) << ' ';
return 0;
}
FFT(三次变两次)
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define db double
using namespace std;
const db pi=acos(-1);
struct cp { db x, y; };
typedef const cp ccp;
cp operator+(ccp &a,ccp &b) { return (cp){a.x+b.x,a.y+b.y}; }
cp operator-(ccp &a,ccp &b) { return (cp){a.x-b.x,a.y-b.y}; }
cp operator*(ccp &a,ccp &b) { return (cp){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x}; }
vector<cp> w[20];
void init(int m) {
for(int i=1; (1<<i)<=m; ++i) {
int n=(1<<i); w[i].resize(n>>1);
up(j,0,(n>>1)-1) w[i][j]=(cp){cos(2*j*pi/n),sin(2*j*pi/n)};
}
}
void dft(vector<cp> &f) {
int n=f.size();
if(n==1) return;
vector<cp> f0(n>>1), f1(n>>1);
up(i,0,n-1) if(i&1) f1[i>>1]=f[i]; else f0[i>>1]=f[i];
dft(f0), dft(f1);
int id=0; while((1<<id)<n) ++id;
up(i,0,(n>>1)-1) {
cp tmp=w[id][i]*f1[i];
f[i]=f0[i]+tmp, f[i+(n>>1)]=f0[i]-tmp;
}
}
void idft(vector<cp> &f) {
int n=f.size();
dft(f), reverse(&f[1],&f[n]);
up(i,0,n-1) f[i].x/=n, f[i].y/=n;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n, m, N=1;
cin >> n >> m;
while(N<=n+m) N<<=1;
init(N); vector<cp> f(N);
up(i,0,n) cin >> f[i].x;
up(i,0,m) cin >> f[i].y;
dft(f);
up(i,0,N-1) f[i]=f[i]*f[i];
idft(f);
up(i,0,n+m) {
int res=f[i].y*0.5+0.1;
cout << res << ' ';
}
return 0;
}
NTT
lnk,常见素数及其原根。
#include<bits/stdc++.h>
#define int long long
#define db long double
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int P=998244353, G=3, N=1350000;
int ksm(int a,int b=P-2) {
int res=1;
for( ; b; b>>=1) {
if(b&1) res=res*a%P;
a=a*a%P;
}
return res;
}
int n, m, tr[N<<1], f[N<<1], g[N<<1], invn, invG=ksm(G);
void NTT(int *f,bool op) {
up(i,0,n-1) if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int p=2; p<=n; p<<=1) {
int len=p>>1, tG=ksm(op?G:invG,(P-1)/p);
for(int k=0; k<n; k+=p) {
int buf=1;
up(l,k,k+len-1) {
int tt=buf*f[len+l]%P;
f[len+l]=f[l]-tt;
if(f[len+l]<0) f[len+l]+=P;
f[l]=f[l]+tt;
if(f[l]>P) f[l]-=P;
buf=buf*tG%P;
}
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m, ++n, ++m;
up(i,0,n-1) cin >> f[i];
up(i,0,m-1) cin >> g[i];
for(m+=n, n=1; n<m; n<<=1);
up(i,0,n-1) tr[i]=(tr[i>>1]>>1)|((i&1)?n>>1:0);
NTT(f,1), NTT(g,1);
up(i,0,n-1) f[i]=f[i]*g[i]%P;
NTT(f,0), invn=ksm(n);
up(i,0,m-2) cout << f[i]*invn%P << ' ';
return 0;
}
Splay 平衡树
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
inline int read() {
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
const int N=8000005, inf=1<<30;
int tot, root, fa[N], son[N][2], val[N], cnt[N], siz[N];
void build() {
tot=2, val[1]=inf, val[2]=-inf;
son[1][0]=2, root=fa[2]=1;
}
void upt(int x) { siz[x]=cnt[x]+siz[son[x][0]]+siz[son[x][1]]; }
void rotato(int x) {
int y=fa[x], z=fa[y];
if(z) son[z][son[z][1]==y]=x; fa[x]=z;
bool k=(son[y][1]==x);
son[y][k]=son[x][k^1], fa[son[x][k^1]]=y;
son[x][k^1]=y, fa[y]=x;
upt(y), upt(x), upt(z);
}
void splay(int x,int goal) {
while(fa[x]!=goal) {
int y=fa[x], z=fa[y];
if(z!=goal) (x==son[y][0])^(y==son[z][0])?rotato(x):rotato(y);
rotato(x);
}
if(!goal) root=x;
}
void find(int v) {
int x=root;
while(val[x]!=v&&son[x][v>val[x]]) x=son[x][v>val[x]];
splay(x,0);
}
void Insert(int v) {
int x=root, fad=0;
while(x&&val[x]!=v) fad=x, x=son[x][v>val[x]];
if(x) ++cnt[x];
else {
x=++tot;
if(fad) son[fad][v>val[fad]]=x, fa[x]=fad;
val[x]=v, cnt[x]=1;
}
splay(x,0);
}
int Next(int v,int f) {
find(v);
int x=root;
if((val[x]<v&&!f)||(val[x]>v&&f)) return x;
x=son[x][f];
while(son[x][f^1]) x=son[x][f^1];
splay(x,0);
return x;
}
void Delete(int v) {
int pre=Next(v,0), nxt=Next(v,1);
splay(pre,0), splay(nxt,pre);
int del=son[nxt][0];
if(val[del]!=v) return;
if(cnt[del]>1) --cnt[del], splay(del,0);
else son[nxt][0]=0, splay(nxt,0);
}
int kth(int v) {
int x=root;
if(siz[x]<v) return 0;
while(1) {
int y=son[x][0];
if(v>siz[y]+cnt[x]) v-=siz[y]+cnt[x], x=son[x][1];
else {
if(siz[y]>=v) x=y;
else {
splay(x,0);
return val[x];
}
}
}
}
int Rank(int v) {
int pre=Next(v,0);
splay(pre,0);
return siz[son[pre][0]]+cnt[pre]+1;
}
signed main() {
build();
int n, m, opt, x, lst=0, Ans=0;
n=read(), m=read();
while(n--) Insert(read());
while(m--) {
opt=read(), x=read()^lst;
if(opt==1) Insert(x);
if(opt==2) Delete(x);
if(opt==3) lst=Rank(x), Ans^=lst;
if(opt==4) lst=kth(x), Ans^=lst;
if(opt==5) lst=val[Next(x,0)], Ans^=lst;
if(opt==6) lst=val[Next(x,1)], Ans^=lst;
}
cout << Ans;
return 0;
}
Splay 区间反转
#include<bits/stdc++.h>
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
inline int read() {
int X=0; bool flag=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
if(flag) return X;
return ~(X-1);
}
const int N=8000005, inf=1<<30;
int n, m;
int son[N][2], siz[N], root, tag[N], fa[N];
void build(int n) {
root=1;
up(i,2,n) fa[i]=i-1, son[i-1][1]=i;
up(i,1,n) siz[i]=n-i+1;
}
inline void tup(int x) {
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
}
inline void tagrev(int x) {
tag[x]^=1, swap(son[x][0],son[x][1]);
}
void tdn(int x) {
if(tag[x]) tagrev(son[x][0]), tagrev(son[x][1]), tag[x]=0;
}
void rotato(int x) {
int y=fa[x], z=fa[y];
if(z) son[z][son[z][1]==y]=x; fa[x]=z;
bool k=(son[y][1]==x);
son[y][k]=son[x][k^1], fa[son[x][k^1]]=y;
son[x][k^1]=y, fa[y]=x;
tup(y), tup(x); if(z) tup(z);
}
void splay(int x,int goal) {
while(fa[x]!=goal) {
int y=fa[x], z=fa[y];
if(z!=goal) (x==son[y][0])^(y==son[z][0])?rotato(x):rotato(y);
rotato(x);
}
if(!goal) root=x;
}
int kth(int v) {
int x=root;
while(1) {
tdn(x);
int y=son[x][0];
if(v>siz[y]+1) v-=siz[y]+1, x=son[x][1];
else {
if(siz[y]>=v) x=y;
else {
splay(x,0);
return x;
}
}
}
}
void flip(int l,int r) {
int L=kth(l-1), R=kth(r+1);
splay(L,0), splay(R,L), tagrev(son[son[L][1]][0]);
}
void dfs(int x) {
tdn(x);
if(son[x][0]) dfs(son[x][0]);
if(1<x&&x<n) cout << x-1 << ' ';
if(son[x][1]) dfs(son[x][1]);
}
signed main() {
build(n=read()+2), m=read();
while(m--) {
int l, r;
l=read()+1, r=read()+1;
flip(l,r);
}
dfs(root);
return 0;
}
后缀数组
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=1000100;
int n, m, x[N], y[N], c[N], sa[N];
char s[N];
void SA() {
m=122;
up(i,1,m) c[i]=0;
up(i,1,n) x[i]=s[i], c[x[i]]++;
up(i,2,m) c[i]+=c[i-1];
up(i,1,n) sa[c[x[i]]--]=i;
for(int k=1; k<=n; k<<=1) {
int num=0;
up(i,n-k+1,n) y[++num]=i;
up(i,1,n) if(sa[i]>k) y[++num]=sa[i]-k;
up(i,1,m) c[i]=0;
up(i,1,n) c[x[i]]++;
up(i,2,m) c[i]+=c[i-1];
dn(i,n,1) sa[c[x[y[i]]]--]=y[i];
up(i,1,n) y[i]=x[i], x[i]=0;
num=1, x[sa[1]]=1;
up(i,2,n) {
if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) x[sa[i]]=num;
else x[sa[i]]=++num;
}
if(num==n) break; m=num;
}
}
signed main() {
scanf("%s", s+1), n=strlen(s+1);
SA();
up(i,1,n) cout << sa[i] << ' ';
return 0;
}
KMP
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=1000100;
int n, m, f[N], g[N], j;
char a[N], b[N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> (b+1), cin >> (a+1);
m=strlen(b+1), n=strlen(a+1);
up(i,2,n) {
while(j&&a[j+1]!=a[i]) j=g[j];
j+=(a[j+1]==a[i]), g[i]=j;
}
j=0;
up(i,1,m) {
while(j&&(a[j+1]!=b[i]||j==n)) j=g[j];
j+=(a[j+1]==b[i]), f[i]=j;
if(f[i]==n) cout << i-n+1 << '\n';
}
up(i,1,n) cout << g[i] << ' ';
return 0;
}
2-SAT
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back
using namespace std;
const int N=2000010, M=2000010;
int n, m, vis[N], dfn[N], low[N], tc, cnt, bel[N];
int hd[N], nxt[M], to[M], tot=1, stk[N], top;
void eadd(int u,int v) { nxt[++tot]=hd[u], hd[u]=tot, to[tot]=v; }
void tarjan(int x) {
low[x]=dfn[x]=++tc;
vis[x]=1, stk[++top]=x;
for(int i=hd[x]; i; i=nxt[i]) {
int y=to[i];
if(vis[y]==2) continue;
if(!vis[y]) tarjan(y);
low[x]=min(low[x],low[y]);
}
if(dfn[x]==low[x]) {
int p; ++cnt;
while(stk[top+1]!=x) {
p=stk[top--];
vis[p]=2, bel[p]=cnt;
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
up(k,1,m) {
int i, a, j, b, l, r;
cin >> i >> a >> j >> b;
l=(2*i)^(!a), r=(2*j)^(!b);
eadd(l^1,r), eadd(r^1,l);
}
up(i,2,2*n+1) if(!dfn[i]) tarjan(i);
up(i,1,n) if(bel[2*i]==bel[(2*i)^1]) { cout << "IMPOSSIBLE"; return 0; }
cout << "POSSIBLE\n";
up(i,1,n) if(bel[2*i]<bel[(2*i)^1]) cout << 1 << ' '; else cout << 0 << '\n';
return 0;
}
线性基
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back
using namespace std;
const int N=111;
int n, a, mg[N];
void add(int x) {
dn(i,60,0) if(x>>i&1) {
if(mg[i]) x=x^mg[i];
else { mg[i]=x; break; }
}
}
int ask() {
int res=0;
dn(i,60,0) if((res^mg[i])>>i&1)
res=res^mg[i];
return res;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
up(i,1,n) cin >> a, add(a);
cout << ask();
return 0;
}
欧拉回路
#include<bits/stdc++.h>
#define int long long
#define ldb long double
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back
using namespace std;
const int N=500005;
int n, m, in[N], out[N], cur[N], s, t;
vector<int> F[N], Ans;
void dfs(int x) {
for(int i=cur[x]; i<F[x].size(); i=cur[x])
++cur[x], dfs(F[x][i]);
Ans.pb(x);
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
up(i,1,m) {
int u, v;
cin >> u >> v;
++out[u], ++in[v];
F[u].pb(v);
}
up(i,1,n) {
if(in[i]+1==out[i]&&!s) s=i;
else if(out[i]+1==in[i]&&!t) t=i;
else if(in[i]!=out[i]) { cout << "No"; return 0; }
}
up(i,1,n) sort(F[i].begin(),F[i].end());
dfs(max(1ll,s));
dn(i,Ans.size()-1,0) cout << Ans[i] << ' ';
return 0;
}
高斯消元
#include<bits/stdc++.h>
#define db double
#define up(i,l,r) for(register int i=l; i<=r; ++i)
#define dn(i,r,l) for(register int i=r; i>=l; --i)
using namespace std;
const int N=105;
int n; db g[N][N];
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n;
up(i,1,n) up(j,1,n+1) cin >> g[i][j];
up(i,1,n) {
int now=i;
up(j,i+1,n) if(fabs(g[now][i])<fabs(g[j][i])) now=j;
up(j,i,n+1) swap(g[now][j],g[i][j]);
if(g[i][i]==0) { cout << "No Solution"; return 0; }
up(j,i+1,n+1) g[i][j]/=g[i][i];
g[i][i]=1;
up(j,i+1,n) {
up(k,i+1,n+1) g[j][k]-=g[j][i]*g[i][k];
g[j][i]=0;
}
}
dn(i,n,1) {
up(j,i+1,n) {
g[i][n+1]-=g[i][j]*g[j][n+1];
g[i][j]=0;
}
g[i][n+1]/=g[i][i], g[i][i]=1;
}
up(i,1,n) cout << fixed << setprecision(2) << g[i][n+1] << '\n';
return 0;
}