我要复习所有的模板

二分 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)\) 再简单乘即可。

\[ax_1+by_1=\gcd(a,b)=bx_2+(a\mod b)y_2 \]

\[=bx_2+(a-b\lfloor\frac{a}{b}\rfloor)y_2=ay_2+(x_2-\lfloor\frac{a}{b}\rfloor y_2)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

\[\phi(n)=n\prod_{p 是 n 的质因子}\frac{p-1}{p} \]

\[\mu(n)=\begin{cases}(-1)^{n 的质因子数量}&n没有平方因子\\0&otherwise\end{cases} \]


杜教筛

具体过程如 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_i=\sum_{j=i}^n[a_j<a_i],Ans=1+\sum_{i=1}^n A_i\times (n-i)! \]

考虑比 \(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);

点双联通分量、广义圆方树

首先点双在搜索栈里面考虑就行了,建图可以使用广义圆方树,就是对于每一个点双建立一个方点,然后向所在的分量的圆点连边,这样子可以保证性质不变,注意方点要开两倍空间,重边要特判。

image

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&&sum; 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&&sum; 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;
}
posted @ 2024-05-13 16:12  Hypoxia571  阅读(30)  评论(0编辑  收藏  举报