下笔春蚕食叶声。

acm板子整理

板子

备忘

缺省源

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls(x) ((x)<<1)
#define rs(x) ((x)<<1|1)
#define mkp make_pair
#define fi first
#define se second
#define PII pair<int, int>
inline void rd(int &x) {
    x = 0; int tp = 0; char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') tp = 1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    if(tp) x = -x; return;
}
inline void rdll(ll &x) {
    x = 0; int tp = 0; char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') tp = 1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    if(tp) x = -x; return;
}
int main() {
    freopen("ex.in", "r", stdin);
    freopen("ex.out", "w", stdout);

    return 0;
}

运算符重载

struct node {
	int x;
	node(int val) {
		x = val;
	}
	bool operator < (const node a) const {
		return x > a.x;
	}
};

最小表示法

int n,a[600010],ans;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		a[i+n]=a[i];
	} 
	int it1=1,it2=2,l;
	while(it1<=n&&it2<=n){
		l=0;
		while(l<=n&&a[it1+l]==a[it2+l]) l++;
		if(l==n){
			ans=it1;break;
		}
		if(a[it1+l]>a[it2+l]) it1=it1+l+1;
		else it2=it2+l+1;
		if(it1==it2) it2++;
	}
	ans=min(it1,it2);
	for(int i=ans;i<=ans+n-1;i++){
		printf("%d ",a[i]);
	}
	return 0;
}

最长公共子序列

const int N=1e5+10;
int a[N],b[N],f[N],p[N],len=0;
int find(int x){
    int l=1,r=len,ans=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(p[f[mid]]>p[x]) r=mid-1;
        else l=mid+1,ans=mid;
    }
    return ans+1;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) scanf("%d",&b[i]),p[b[i]]=i;
    for(int i=1;i<=n;i++){
        if(p[a[i]]>p[f[len]]) f[++len]=a[i];
        else f[find(a[i])]=a[i];
    }
    printf("%d\n",len);
    return 0;
}

2-SAT

const int N = 2e6 + 10;
int n, m, tim, col[N], tot;
int st[N], top, ins[N], dfn[N], low[N];
int e, to[N], nxt[N], hd[N];
void add(int u, int v) {
    to[++e] = v; nxt[e] = hd[u]; hd[u] = e;
}
void tarjan(int u) {
    low[u] = dfn[u] = ++tim; st[++top] = u; ins[u] = 1;
    for(int i = hd[u]; i; i = nxt[i]) {
        int v = to[i];
        if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
        else if(ins[v]) low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]) {
        ++tot;
        while(top > 0) {
            int x = st[top]; top--; 
            col[x] = tot; ins[x] = 0;
            if(x == u) break;
        }
    }
    return;
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1, u, v, a, b; i <= m; i++) {
        scanf("%d%d%d%d", &u, &a, &v, &b);
        add(u + (a ^ 1) * n, v + b * n);
        add(v + (b ^ 1) * n, u + a * n);
    }
    for(int i = 1; i <= 2 * n; i++)
        if(!dfn[i]) tarjan(i);
    for(int i = 1; i <= n; i++)
        if(col[i] == col[i + n])
            return puts("IMPOSSIBLE"), 0;
    puts("POSSIBLE");
    for(int i = 1; i <= n; i++)
        printf("%d ", (col[i] < col[i + n]) ? 0 : 1);
    return 0;
}

矩阵树

const int N = 310, mod = 1e9 + 7;
int n, a[N][N];
int det(int p) {
    int ans = 1;
    for(int i = 1; i <= p; i++) {
        for(int j = i + 1; j <= p; j++) {
            while(a[i][i]) {
                int t = a[j][i] / a[i][i];
                for(int k = 1; k <= p; k++) 
                    a[j][k] = (a[j][k] + mod - 1ll * t * a[i][k] % mod) % mod;
                for(int k = 1; k <= p; k++) swap(a[i][k], a[j][k]); ans = mod - ans;
            } 
            for(int k = 1; k <= p; k++) swap(a[i][k], a[j][k]); ans = mod - ans;
        }
        ans = 1ll * ans * a[i][i] % mod;
    }
    return ans;
}

int main(){
    // freopen("ex.in", "r", stdin);
    // freopen("ex.out", "w", stdout);
    int n, m, t; scanf("%d%d%d", &n, &m, &t);
    if(t == 0) {
        for(int i = 1, u, v, w; i <= m; i++) {
            scanf("%d%d%d", &u, &v, &w);
            a[u][u] = (a[u][u] + w) % mod;
            a[v][v] = (a[v][v] + w) % mod;
            a[u][v] = (a[u][v] + mod - w) % mod;
            a[v][u] = (a[v][u] + mod - w) % mod;
        }
    } else {
        for(int i = 1, u, v, w; i <= m; i++) {
            scanf("%d%d%d", &u, &v, &w);
            a[v][v] = (a[v][v] + w) % mod;
            a[u][v] = (a[u][v] + mod - w) % mod;
        }
        for(int i = 1; i <= n; i++)
            swap(a[1][i], a[n][i]);
        for(int i = 1; i <= n; i++)
            swap(a[i][1], a[i][n]);
    }
    printf("%d\n", det(n - 1));
    return 0;
}

跳舞链

const int N = 510, M = 5000 + N;
int n, m, cnt, tot;
int l[M], r[M], u[M], d[M], row[M], col[M], s[N], ans[N];
void init() {
	for(int i = 0; i <= m; i++) {
		l[i] = i - 1; r[i] = i + 1;
		u[i] = d[i] = i;
		s[i] = 0;
	}
	l[0] = m; r[m] = 0;
	cnt = m;
	return;
} 
void ins(int &hd, int &tl, int x, int y) {
	++cnt;
	row[cnt] = x; col[cnt] = y; s[y]++;
	u[cnt] = y; d[cnt] = d[y]; u[d[y]] = cnt; d[y] = cnt;
	l[hd] = r[tl] = cnt; r[cnt] = hd; l[cnt] = tl; tl = cnt;	
	return;
}
void remove(int p) {
	//删去列p,和列p为1的所有行
	r[l[p]] = r[p]; l[r[p]] = l[p]; 
	for(int i = d[p]; i != p; i = d[i]) {
		for(int j = r[i]; j != i; j = r[j]) {
			u[d[j]] = u[j]; d[u[j]] = d[j];
			s[col[j]]--;
		}
	}  
}
void recover(int p) {
	for(int i = u[p]; i != p; i = u[i]) {
		for(int j = l[i]; j != i; j = l[j]) {
			u[d[j]] = j; d[u[j]] = j;
			s[col[j]]++;
		}
	}  
	//增加列p为1的所有行,增加列p 
	r[l[p]] = p; l[r[p]] = p; 
}
bool dfs() {
	
	if(!r[0]) return 1;
	int p = r[0];
	for(int i = r[0]; i; i = r[i])
		if(s[i] < s[p]) p = i;
	remove(p);
	for(int i = d[p]; i != p; i = d[i]) {
		ans[++tot] = row[i];
		for(int j = r[i]; j != i; j = r[j])
			remove(col[j]);
		if(dfs()) return 1;
		for(int j = l[i]; j != i; j = l[j])
			recover(col[j]);
		--tot;
	}
	recover(p);
	return 0;
}
int main(){
//	freopen("qwq.txt", "r", stdin);
	scanf("%d%d", &n, &m);
	init();
	for(int i = 1; i <= n; i++) {
		
		int hd = cnt + 1, tl = cnt + 1;
		for(int j = 1, x; j <= m; j++) {
			scanf("%d", &x);
			if(x) ins(hd, tl, i, j);
		}
	}
	if(dfs()) {
		for(int i = 1; i <= tot; i++)
			printf("%d ", ans[i]);
		puts("");
	} else
		puts("No Solution!");
	return 0;
}

树同构

const int N=55,mod=1019260817,bs=19491001,inf=0x3f3f3f3f;
int rt,rt2;
int e,to[N<<1],nxt[N<<1],hd[N];
int sz[N],maxp[N],val[N],dep[N],pw[N];
struct node{
    int x,y;
    bool operator < (const node a) const { return (x==a.x)?y<a.y:x<a.x; }   
    bool operator == (const node a) const { return (x==a.x&&y==a.y); }   
}tr[N],son[N];
int n,m;
void add(int a,int b){ to[++e]=b; nxt[e]=hd[a]; hd[a]=e; }
int bmax(int x,int y){ return (x>y)?x:y; }
int bmin(int x,int y){ return (x<y)?x:y; }
void getrt(int u,int fa){
    sz[u]=1; maxp[u]=0;
    for(int i=hd[u];i;i=nxt[i]){
        int v=to[i]; if(v==fa) continue;
        getrt(v,u);
        sz[u]+=sz[v]; maxp[u]=bmax(maxp[u],sz[v]);
    }
    maxp[u]=bmax(maxp[u],n-sz[u]);
    if(maxp[rt]==maxp[u]) rt2=u;
    if(maxp[rt]>maxp[u]) rt=u,rt2=0;
    return;
}
void dfs(int u,int fa){
    int tot=0;
    sz[u]=1,val[u]=1ll*dep[u]*pw[sz[u]]%mod;
    for(int i=hd[u];i;i=nxt[i]){
        int v=to[i]; if(v==fa) continue;
        dep[v]=dep[u]+1; dfs(v,u);
    }
    for(int i=hd[u];i;i=nxt[i]){
        int v=to[i]; if(v==fa) continue;
        son[++tot]=(node){val[v],sz[v]};
    }
    sort(son+1,son+tot+1);
    for(int i=1;i<=tot;i++)
        val[u]=(val[u]+1ll*son[i].x*pw[sz[u]]%mod)%mod,sz[u]+=son[i].y;
    val[u]=(val[u]+mod)%mod;
   // cout<<u<<" "<<val[u]<<endl;
    return;
}
node ins(){
    e=0; memset(hd,0,sizeof(hd));
    int reta=0,retb=0;
    scanf("%d",&n);
    for(int i=1,fat;i<=n;i++){
        scanf("%d",&fat);
        if(fat!=0) add(i,fat); add(fat,i);
    }
    rt=0,rt2=0; maxp[0]=inf;
    getrt(1,0);
    //cout<<rt<<"*"<<rt2<<" "<<maxp[rt]<<" "<<maxp[rt2]<<endl;
  //  cout<<"----"<<endl;
    if(rt) dep[rt]=1,dfs(rt,0),reta=val[rt];
  //  cout<<"----"<<endl;
    if(rt2) dep[rt2]=1,dfs(rt2,0),retb=val[rt2];
    if(reta<retb) swap(reta,retb);
    return (node){reta,retb};
}
int main(){
    pw[0]=1;
    for(int i=1;i<=51;i++)
        pw[i]=1ll*pw[i-1]*bs%mod;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
        tr[i]=ins();
    for(int i=1;i<=m;i++){
      //  printf("%d %d\n",tr[i].x,tr[i].y);
        for(int j=1;j<=m;j++)
            if(tr[i]==tr[j]){
                printf("%d\n",j); break;
            }
    }
    return 0;
}
/*
zaky的题解。是模拟赛结束后hehezhou的方法Orz。
https://www.cnblogs.com/zkyJuruo/p/14175062.html
*/

动态DP

const int N = 1e5 + 10, M = 20, lim = 18, inf = 0x3f3f3f3f;
int n, m, dep[N], g[N][2], dy[N], sz[N], fat[N], son[N], dfn[N], tim, top[N], f[N][2], End[N], val[N];
//g:节点i选/不选,与其轻儿子的最大独立集 
int e, to[N << 1], nxt[N << 1], hd[N];
struct Matrix {
	int mat[2][2];
	Matrix(){
		for(int i = 0; i < 2; i++)
			for(int j = 0; j < 2; j++)
				mat[i][j] = -inf;
	}
	inline void init_e() { for(int i = 0; i < 2; i++) mat[i][i] = 0; }
	friend Matrix operator * (Matrix x, Matrix y) {
		Matrix z; 
		for(int i = 0; i < 2; i++)
			for(int j = 0; j < 2; j++)
				for(int k = 0; k < 2; k++)
					z.mat[i][j] = max(z.mat[i][j], x.mat[i][k] + y.mat[k][j]);
		return z;
	}
}trans[N], tr[N << 2];
inline Matrix calc_trans(int x, int y) {
	Matrix z;
	z.mat[0][0] = z.mat[1][0] = x;
	z.mat[0][1] = y;
	return z;
}
void build(int rt, int l, int r) {
	if(l == r) {
		tr[rt] = trans[dy[l]]; return; 
	}
	int mid = (l + r) >> 1;
	build(ls(rt), l, mid); build(rs(rt), mid + 1, r);
	tr[rt] = tr[rs(rt)] * tr[ls(rt)];
}
void update(int rt, int l, int r, int pos) {
	if(l == r) {
		tr[rt] = trans[dy[l]]; return; 
	}
	int mid = (l + r) >> 1;
	if(pos <= mid) update(ls(rt), l, mid, pos);
	else update(rs(rt), mid + 1, r, pos);
	tr[rt] = tr[rs(rt)] * tr[ls(rt)];
}
Matrix query(int rt, int l, int r, int L, int R) {
//	cout<<l<<" "<<r<<" "<<L<<" "<<R<<endl;
	if(L <= l && r <= R) {
//		cout<<tr[rt].mat[0][0]<<" "<<tr[rt].mat[0][1]<<endl;
		return tr[rt];
	}
	int mid = (l + r) >> 1;
	if(R <= mid) return query(ls(rt), l, mid, L, R); 
	else if(L > mid) return query(rs(rt), mid + 1, r, L, R); 
	else return query(rs(rt), mid + 1, r, L, R) * query(ls(rt), l, mid, L, R); 
}


void add(int u, int v) { to[++e] = v; nxt[e] = hd[u]; hd[u] = e; }
void dfs1(int u, int fa) {
	dep[u] = dep[fa] + 1; sz[u] = 1; fat[u] = fa;
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fa) continue;
		dfs1(v, u); sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v;
	}
}
void dfs2(int u, int topf) {
	dfn[u] = ++tim; dy[tim] = u;
	top[u] = topf; End[topf] = tim;
	f[u][0] = 0; f[u][1] = val[u]; g[u][0] = 0; g[u][1] = val[u];
	if(son[u]) {
		dfs2(son[u], topf);
		f[u][0] += max(f[son[u]][0], f[son[u]][1]); f[u][1] += f[son[u]][0];
	}
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fat[u] || v == son[u]) continue;
		dfs2(v, v);
		f[u][0] += max(f[v][0], f[v][1]); f[u][1] += f[v][0];
		g[u][0] += max(f[v][0], f[v][1]); g[u][1] += f[v][0];
	}
}
void modify_path(int u, int w) {
	trans[u].mat[0][1] += w - val[u]; val[u] = w;
	while(u != 0) {
		int topf = top[u];
		Matrix lst = query(1, 1, n, dfn[topf], End[topf]);
		update(1, 1, n, dfn[u]);
		Matrix nw = query(1, 1, n, dfn[topf], End[topf]);
		trans[fat[topf]].mat[0][0] += max(nw.mat[0][0], nw.mat[0][1]) - max(lst.mat[0][0], lst.mat[0][1]); trans[fat[topf]].mat[1][0] = trans[fat[topf]].mat[0][0];
		trans[fat[topf]].mat[0][1] += nw.mat[0][0] - lst.mat[0][0];
		u = fat[topf];
	}
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%d", &val[i]);
	for(int i = 1, u, v; i < n; i++)
		scanf("%d%d", &u, &v), add(u, v), add(v, u);
	dfs1(1, 0); dfs2(1, 1);
	for(int i = 1; i <= n; i++)
		trans[i] = calc_trans(g[i][0], g[i][1]);
	build(1, 1, n);
	while(m--) {
		int x, y; scanf("%d%d", &x, &y);
		modify_path(x, y);
		Matrix ans = query(1, 1, n, dfn[1], End[1]);
		printf("%d\n", max(ans.mat[0][0], ans.mat[0][1]));
	}
	return 0;
}

三维偏序

const int N = 1e5 + 10; 
int n, k;
struct node {
	int a, b, c, w, id;
	friend bool operator < (node &x, node &y) {
		if(x.a != y.a) return x.a < y.a;
		if(x.b != y.b) return x.b < y.b;
		return x.c < y.c;
	}
	friend bool operator != (node &x, node &y) {
		return (x.a != y.a || x.b != y.b || x.c != y.c);
	}
}flo[N], tmp[N];
int tot[N], res[N];
int lowbit(int x) {
	return x & -x;
}
int tr[200010], ans[N];
void ins(int x, int val) {
	for(; x <= k; x += lowbit(x)) {
		tr[x] += val;
	}
}
int query(int x) {
	int ret = 0;
	for(; x; x -= lowbit(x)) {
		ret += tr[x];
	}
	return ret;
}
void cdq(int l, int r) {
	if(l == r) return;
	int mid = (l + r) >> 1;
	cdq(l, mid); cdq(mid + 1, r);
	int i = l, j = mid + 1, len = 0;
	while(i <= mid || j <= r) {
		if(j > r || i <= mid && flo[i].b <= flo[j].b) {
			ins(flo[i].c, flo[i].w);
			tmp[++len] = flo[i];
			i++;	
		} else {
			ans[flo[j].id] += query(flo[j].c);
		//	cout<<flo[j].id<<": "<<query(flo[j].c)<<endl;
			tmp[++len] = flo[j];
			j++;
		}
	}
	for(int i = l; i <= mid; i++)
		ins(flo[i].c, -flo[i].w);
	for(int i = l; i <= r; i++)
		flo[i] = tmp[i - l + 1];
	return;
}
int main() {
//    freopen("ex.in", "r", stdin);
//    freopen("ex.out", "w", stdout);
	rd(n); rd(k);
	for(int i = 1; i <= n; i++) {
		rd(flo[i].a); rd(flo[i].b); rd(flo[i].c);
	}
	sort(flo + 1, flo + n + 1);
	int lst = 1, m = 0;
	for(int i = 1; i <= n; i++)
		if(flo[i] != flo[lst]) {
			flo[++m] = flo[lst]; flo[m].w = i - lst;
			flo[m].id = m; tot[m] = i - lst;
			//cout<<flo[m].a<<" "<<flo[m].b<<" "<<flo[m].c<<": "<<tot[m]<<endl;
			lst = i;
		}
	flo[++m] = flo[lst]; flo[m].w = n + 1 - lst;
	flo[m].id = m; tot[m] = n + 1 - lst;
	//cout<<flo[m].a<<" "<<flo[m].b<<" "<<flo[m].c<<": "<<tot[m]<<endl;
	cdq(1, m);
//	for(int i = 1; i <= m; i++)
//		cout<<ans[i]<<" "<<tot[i]<<endl;
	for(int i = 1; i <= m; i++)
		res[ans[i] + tot[i] - 1] += tot[i];
	for(int i = 0; i < n; i++)
		printf("%d\n", res[i]);
	puts("");
    return 0;
}

数据结构

单调队列

//滑动窗口找最小值
//队列内单调递增
int h = 1, t = 0;
for(int i = 1; i <= n; i++) {
	while(h <= t && q[h] <= i - k) h++;
	while(h <= t && a[q[t]] >= a[i]) t--;
	q[++t] = i;
	if(i >= k) printf("%d ", a[q[h]]);
}
puts("");

单调栈

//找最近的比它大的
//栈顶到栈底单调递增
int top = 0;
for(int i = n; i >= 1; i--) {
	while(top && a[st[top]] <= a[i]) top--;
	ans[i] = st[top];
	st[++top] = i;
}

线段树:区间乘 区间加 区间求和

void Add(int &x, int y) {
	x += y; if(x >= mod) x -= mod;
}
void workmul(int rt, int mul) {
	tr[rt] = (ll)tr[rt] * mul % mod;
	lz_mul[rt] = (ll)lz_mul[rt] * mul % mod;
	lz_add[rt] = (ll)lz_add[rt] * mul % mod;
}
void workadd(int rt, int add) {
	Add(tr[rt], (ll)add * len[rt] % mod);
	Add(lz_add[rt], add);
}
void pushdown(int rt) {
	workmul(ls(rt), lz_mul[rt]); workadd(ls(rt), lz_add[rt]);
	workmul(rs(rt), lz_mul[rt]); workadd(rs(rt), lz_add[rt]);
	lz_mul[rt] = 1; lz_add[rt] = 0;
	return;
}
void pushup(int rt) {
	tr[rt] = (tr[ls(rt)] + tr[rs(rt)]) % mod;
	return;
} 
void build(int rt, int l, int r) {
	lz_mul[rt] = 1; lz_add[rt] = 0; len[rt] = r - l + 1;
	if(l == r) {
		tr[rt] = a[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(ls(rt), l, mid);
	build(rs(rt), mid + 1, r);
	pushup(rt);
	return;
}
void update_mul(int rt, int l, int r, int L, int R, int k) {
	if(L <= l && r <= R) {
		workmul(rt, k);
		return;
	}
	pushdown(rt);
	int mid = (l + r) >> 1;
	if(L <= mid) update_mul(ls(rt), l, mid, L, R, k);
	if(R > mid) update_mul(rs(rt), mid + 1, r, L, R, k);
	pushup(rt);
	return;
}
void update_add(int rt, int l, int r, int L, int R, int k) {
	if(L <= l && r <= R) {
		workadd(rt, k);
		return;
	}
	pushdown(rt);
	int mid = (l + r) >> 1;
	if(L <= mid) update_add(ls(rt), l, mid, L, R, k);
	if(R > mid) update_add(rs(rt), mid + 1, r, L, R, k);
	pushup(rt);
	return;
}
int query_sum(int rt, int l, int r, int L, int R) {
	if(L <= l && r <= R) return tr[rt];
	pushdown(rt);
	int ret = 0;
	int mid = (l + r) >> 1;
	if(L <= mid) Add(ret, query_sum(ls(rt), l, mid, L, R));
	if(R > mid) Add(ret, query_sum(rs(rt), mid + 1, r, L, R));
	pushup(rt);
	return ret;
}

平衡树

//fhq
const int M = 1e5 + 10;
int cnt = 0, rt;
struct node {
	int l, r, val, pri, tot, sz;
	node() {}
	node(int a, int b, int c, int d, int e, int f) {
		l = a; r = b; val = c; pri = d; tot = e; sz = f;
	}
}tr[M]; 
int newnode(int val) {
	int p = ++cnt;
	tr[p] = node(0, 0, val, rand(), 0, 0);
	return p;
}
void update(int x) {
	tr[x].sz = tr[tr[x].l].sz + tr[tr[x].r].sz + tr[x].tot;
}
int merge(int x, int y) {
	//pri的小根堆 
	if(!x || !y) return x | y;
	if(tr[x].pri < tr[y].pri) {
		tr[x].r = merge(tr[x].r, y);
		update(x);
		return x;
	} else {
		tr[y].l = merge(x, tr[y].l);
		update(y);
		return y;
	}
}
void split(int p, int &x, int &y, int val) {	
	if(!p) return x = y = 0, void();
	int l = tr[p].l, r = tr[p].r;
	if(tr[p].val > val) {
		y = p;
		split(l, x, tr[y].l, val);
	} else {
		x = p;
		split(r, tr[x].r, y, val);
	}
	update(p);
	return;
}
void ins(int val) {
	int x, y, z; 
	split(rt, x, z, val);
	split(x, x, y, val - 1);
	if(!y) y = newnode(val);
	tr[y].tot++; tr[y].sz++;
	rt = merge(merge(x, y), z);
	return;
}
void del(int val) {
	int x, y, z; 
	split(rt, x, z, val);
	split(x, x, y, val - 1);
	tr[y].tot--; tr[y].sz--;
	if(tr[y].tot == 0) {
		rt = merge(x, z);
	} else {
		rt = merge(merge(x, y), z);
	}
}
int getrank(int val) {
	int x, y; 
	split(rt, x, y, val - 1);
	int ret = tr[x].sz + 1;
	rt = merge(x, y);
	return ret;
}
int getnum(int k) {
	int p = rt;
	while(k) {
		int l = tr[p].l, r = tr[p].r;
		if(k <= tr[l].sz) {
			p = l;
		} else if(k <= tr[l].sz + tr[p].tot) {
			return tr[p].val;
		} else {
			k -= tr[l].sz + tr[p].tot;
			p = r;
		}
	}
	return -1;
}
int getpre(int val) {
	int x, y; 
	split(rt, x, y, val - 1);
	int p = x;
	while(tr[p].r) p = tr[p].r;
	rt = merge(x, y);
	return tr[p].val;
}
int getnxt(int val) {
	int x, y; 
	split(rt, x, y, val);
	int p = y;
	while(tr[p].l) p = tr[p].l;
	rt = merge(x, y);
	return tr[p].val;
}
int main() {
	srand(time(0)); 
	int n; scanf("%d", &n);
	for(int cas = 1, op, x; cas <= n; cas++) {
		rd(op); rd(x);
		if(op == 1) {
			ins(x); 
		} else if(op == 2) {
			del(x); 
		} else if(op == 3) {
			printf("%d\n", getrank(x));
		} else if(op == 4) {
			printf("%d\n", getnum(x));
		} else if(op == 5){
			printf("%d\n", getpre(x));
		} else {
			printf("%d\n", getnxt(x));
		}
	}	
    return 0;
} 
//splay
const int N = 1e5 + 10, inf = 0x3f3f3f3f;
int tot, rt;
struct node {
    int fa, val, ch[2], cnt, sz;
    node() {
        fa = val = ch[0] = ch[1] = cnt = sz = 0;
    }
}tr[N];
void update(int x) {
    tr[x].sz = tr[tr[x].ch[0]].sz + tr[tr[x].ch[1]].sz + tr[x].cnt;
}
void rotate(int x) {
    int y = tr[x].fa, z = tr[y].fa, k = (tr[y].ch[1] == x);
    tr[z].ch[tr[z].ch[1] == y] = x; tr[x].fa = z;
    tr[y].ch[k] = tr[x].ch[k ^ 1]; tr[tr[y].ch[k]].fa = y;
    tr[x].ch[k ^ 1] = y; tr[y].fa = x;
    update(y); update(x);
}
void splay(int x, int goal) {
    while(tr[x].fa != goal) {
        int y = tr[x].fa, z = tr[y].fa;
        if(z != goal) {
            ((tr[y].ch[1] == x) ^ (tr[z].ch[1] == y)) ? rotate(y) : rotate(x);
            rotate(x);
        } else rotate(x);
    }
    if(goal == 0) rt = x;
}
int newnode(int fa, int val) {
    ++tot;
    tr[fa].ch[val > tr[fa].val] = tot;
    tr[tot].fa = fa; tr[tot].val = val;
    tr[tot].ch[0] = tr[tot].ch[1] = 0;
    tr[tot].cnt = tr[tot].sz = 1;
    return tot;
}
void find(int val) {
    int nw = rt;
    while(tr[nw].ch[val > tr[nw].val] && tr[nw].val != val)
        nw = tr[nw].ch[val > tr[nw].val];
    splay(nw, 0);
}
int nxt(int val, int tp) {
    find(val);
    int nw = rt;
    if(tr[nw].val < val && !tp) return nw;
    if(tr[nw].val > val && tp) return nw;
    nw = tr[nw].ch[tp]; while(tr[nw].ch[tp ^ 1]) nw = tr[nw].ch[tp ^ 1];
    return nw;
}
void ins(int val) {
    int nw = rt, fa = 0;
    while(tr[nw].val != val && nw)
        fa = nw, nw = tr[nw].ch[val > tr[nw].val];
    if(nw) tr[nw].cnt++, tr[nw].sz++;
    else nw = newnode(fa, val);
    splay(nw, 0);
}
void del(int val) {
    int x = nxt(val, 0), y = nxt(val, 1);
    splay(x, 0); splay(y, x);
    int nw = tr[y].ch[0];
    if(tr[nw].cnt > 1) tr[nw].cnt--, tr[nw].sz--, splay(nw, 0);
    else tr[y].ch[0] = 0, splay(y, 0);
}
int rk(int val) {
    find(val); return tr[tr[rt].ch[0]].sz;
}
int kth(int nw, int k) {
    k++; if(tr[nw].sz < k) return 0;
    while(nw) {
        int l = tr[nw].ch[0], r = tr[nw].ch[1];
        if(tr[l].sz >= k) { nw = l; continue; }
        k -= tr[l].sz; if(tr[nw].cnt >= k) return nw;
        k -= tr[nw].cnt; nw = r;
    }
    return nw;
}
int main(){

    ins(-inf); ins(inf);
    int n; scanf("%d", &n);
    while(n--) {
        int op, x; scanf("%d%d", &op, &x);
        if(op == 1) ins(x);
        else if(op == 2) del(x);
        else if(op == 3) printf("%d\n", rk(x));
        else if(op == 4) printf("%d\n", tr[kth(rt, x)].val);
        else printf("%d\n", tr[nxt(x, (op == 5 ? 0 : 1))].val);
    }
    return 0;
}
//你就不知道cnt变了sz也会变吗,啊?

扫描线 & 矩阵面积并

const int N = 2e5 + 10;
int lsh[N];
struct ope {
	int l, r, h, val;
	ope() {}
	ope(int a, int b, int c, int d) {
		l = a; r = b; h = c; val = d;
	}
	bool operator < (const ope x) const {
		return h < x.h;
	}
}sq[N];
struct node {
	int l, r, val, sum, lf;
}tr[N << 2];
void pushup(int rt) {
	if(tr[rt].val)
		tr[rt].sum = lsh[tr[rt].r + 1] - lsh[tr[rt].l];
	else {
		if(tr[rt].lf) tr[rt].sum = 0;
		else tr[rt].sum = tr[ls(rt)].sum + tr[rs(rt)].sum;
	}
	return;
}
void build(int rt, int l, int r) {
	tr[rt].l = l; tr[rt].r = r;
	tr[rt].val = tr[rt].sum = 0;
	tr[rt].lf = 0;
	if(l == r) {
		tr[rt].lf = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(ls(rt), l, mid);
	build(rs(rt), mid + 1, r);
	return;
}
void update(int rt, int L, int R, int val) {
	int l = tr[rt].l, r = tr[rt].r;
	if(lsh[l] >= R || lsh[r + 1] <= L) return;
	if(L <= lsh[l] && lsh[r + 1] <= R) {
		tr[rt].val += val;
		pushup(rt);
		return;
	}
	update(ls(rt), L, R, val);
	update(rs(rt), L, R, val);
	pushup(rt);
	return;
}
int main(){
	int n; scanf("%d", &n);
	for(int i = 1, xa, ya, xb, yb; i <= n; i++) {
		scanf("%d%d%d%d", &xa, &ya, &xb, &yb);
		lsh[i * 2 - 1] = xa; lsh[i * 2] = xb; 
		sq[i * 2 - 1] = ope(xa, xb, ya, 1);
		sq[i * 2] = ope(xa, xb, yb, -1);
	}
	n <<= 1;
	sort(lsh + 1, lsh + n + 1);
	int cnt = unique(lsh + 1, lsh + n + 1) - lsh - 1;
	build(1, 1, cnt - 1);
	
	sort(sq + 1, sq + n + 1);
	ll ans = 0;
	for(int i = 1; i < n; i++) {
		update(1, sq[i].l, sq[i].r, sq[i].val);
		ans += 1ll * tr[1].sum * (sq[i + 1].h - sq[i].h);
	}
	printf("%lld\n", ans);
	return 0;
}

左偏树

const int N = 1e5 + 10;
int n, m, f[N], val[N], dis[N], tr[N][2];
int find(int x) { return (x == f[x]) ? x : f[x] = find(f[x]); }
int merge(int x, int y) {
	if(!x || !y) return x | y;
	if(val[x] > val[y] || (val[x] == val[y] && x > y)) swap(x, y); 
	tr[x][1] = merge(tr[x][1], y);
	if(dis[tr[x][0]] < dis[tr[x][1]]) swap(tr[x][0], tr[x][1]);
	f[tr[x][0]] = f[tr[x][1]] = x; //最多也是跳log次。 
	dis[x] = dis[tr[x][1]] + 1;
	return x;
}
void del(int x) {
	val[x] = -1;
	f[tr[x][0]] = tr[x][0]; f[tr[x][1]] = tr[x][1];
	f[x] = merge(tr[x][0], tr[x][1]); //子树中有些点路径压缩到的还是x,让他们跳到正确的根。 
}
int main() {
	dis[0] = -1;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%d", &val[i]), f[i] = i;
	while(m--) {
		int op, x, y;
		scanf("%d", &op);
		if(op == 1) {
			scanf("%d%d", &x, &y);
			if(val[x] == -1 || val[y] == -1) continue;
			x = find(x); y = find(y);
			if(x != y) f[x] = f[y] = merge(x, y);
		} else {
			scanf("%d", &x);
			if(val[x] == -1) { puts("-1"); continue; }
			int y = find(x); printf("%d\n", val[y]); del(y);
		}
	}
	return 0;
}

笛卡尔树

//每个节点的编号满足二叉搜索树的性质。
//每个节点的权值满足小根堆的性质。
inline void rd(int &x) {
    x = 0; int tp = 0; char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') tp = 1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    if(tp) x = -x; return;
}
inline void rdll(ll &x) {
    x = 0; int tp = 0; char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') tp = 1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    if(tp) x = -x; return;
}
const int N = 1e7 + 10;
int n, st[N], top, p[N], ls[N], rs[N]; 
void ins(int x) {
	while(top && p[st[top]] > p[x]) {
		ls[x] = st[top];
		top--; 
	}
	if(st[top]) rs[st[top]] = x;
	st[++top] = x;
}
int main() {
	rd(n);
	for(int i = 1; i <= n; i++)
		rd(p[i]), ins(i);
	ll ansl = 0, ansr = 0;
	for(int i = 1; i <= n; i++) {
		ansl ^= (ll)i * (ls[i] + 1);
		ansr ^= (ll)i * (rs[i] + 1);
	}
	printf("%lld %lld\n", ansl, ansr);
    return 0;
}

主席树,查询区间第k大

const int M = 4e6 + 10, N = 2e5 + 10;
int n, m, cnt, tr[M], ls[M], rs[M], lsh[N], a[N], rt[N]; 
int newnode(int p) {
	int nwp = ++cnt;
	tr[nwp] = tr[p];
	ls[nwp] = ls[p];
	rs[nwp] = rs[p];
	return nwp;
}
void ins(int &p, int l, int r, int pos, int val) {
	p = newnode(p);
	if(l == r) {
		tr[p]++;
		return;
	}
	int mid = (l + r) >> 1;
	if(pos <= mid) ins(ls[p], l, mid, pos, val);
	else ins(rs[p], mid + 1, r, pos, val);
	tr[p] = tr[ls[p]] + tr[rs[p]]; 
}
int query(int x, int y, int l, int r, int k) {
	if(l == r) return l;
	int mid = (l + r) >> 1;
	int tmp = tr[ls[y]] - tr[ls[x]];
	if(tmp >= k) return query(ls[x], ls[y], l, mid, k);
	else return query(rs[x], rs[y], mid + 1, r, k - tmp);
}
int main() {
//	freopen("ex.in", "r", stdin);
	rd(n); rd(m);
	for(int i = 1; i <= n; i++) {
		rd(a[i]);
		lsh[i] = a[i];
	}
	sort(lsh + 1, lsh + n + 1);
	for(int i = 1; i <= n; i++) {
		a[i] = lower_bound(lsh + 1, lsh + n + 1, a[i]) - lsh;
		rt[i] = rt[i - 1];
		ins(rt[i], 1, n, a[i], 1);
	}
	for(int i = 1; i <= m; i++) {
		int l, r, k;
		rd(l); rd(r); rd(k);
		int t = query(rt[l - 1], rt[r], 1, n, k);
		printf("%d\n", lsh[t]);
	}
	return 0;
}

可持久化线段树1,查询历史版本

const int N = 1e6 + 10;
struct node {
    int l, r, val;
}tr[N * 2 * 20];
int n, m, cnt, rt[N], a[N];
int newnode(int x) { tr[++cnt] = tr[x]; return cnt; }
void ins(int &x, int l, int r, int loc, int val) {
    x = newnode(x);
    if(l == r) { return tr[x].val = val, void(); }
    int mid = (l + r) >> 1;
    if(loc <= mid) ins(ls(x), l, mid, loc, val);
    else ins(rs(x), mid + 1, r, loc, val);
    return;
}
void build(int &x, int l, int r) {
    x = newnode(x);
    if(l == r) return tr[x].val = a[l], void();
    int mid = (l + r) >> 1;
    build(ls(x), l, mid);
    build(rs(x), mid + 1, r);
    return;
}
int query(int x, int l, int r, int loc) {
    if(l == r) return tr[x].val; 
    int mid = (l + r) >> 1;
    if(loc <= mid) return query(ls(x), l, mid, loc);
    else return query(rs(x), mid + 1, r, loc);
}
int main() {
   // freopen("ex.in", "r", stdin);
   // freopen("ex.out", "w", stdout);
    rd(n); rd(m);
    for(int i = 1; i <= n; i++) rd(a[i]);
    build(rt[0], 1, n);
    for(int i = 1, v, loc, val, op; i <= m; i++) {
        rd(v); rd(op);
        rt[i] = rt[v];
        if(op == 1) {
            rd(loc), rd(val);
            ins(rt[i], 1, n, loc, val);
        } else {
            rd(loc);
            printf("%d\n", query(rt[i], 1, n, loc));
        }
    }
    return 0;
}

回滚莫队

const int N = 2e5 + 10, B = 450, inf = 0x3f3f3f3f;
int n, q, a[N], lsh[N], id[N], mn[N], mx[N], mx2[N], mn2[N], res[N], ans, nwans;
struct ques {
	int l, r, askid;
	bool operator < (const ques &x) const {
		return (id[l] == id[x.l]) ? r < x.r : id[l] < id[x.l];
	}
}que[N];
void update(int i) {
	mn[a[i]] = min(mn[a[i]], i); mx[a[i]] = max(mx[a[i]], i);
	nwans = max(nwans, mx[a[i]] - mn[a[i]]);
}
void update2(int i) {
	mn2[a[i]] = min(mn2[a[i]], i); mx2[a[i]] = max(mx2[a[i]], i);
	ans = max(ans, max(mx[a[i]], mx2[a[i]]) - min(mn[a[i]], mn2[a[i]]));
}
void update3(int i) {
	mn2[a[i]] = min(mn2[a[i]], i); mx2[a[i]] = max(mx2[a[i]], i);
	ans = max(ans, mx2[a[i]] - mn2[a[i]]);
}
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		scanf("%d", &a[i]), lsh[i] = a[i], id[i] = (i - 1) / B + 1;
	sort(lsh + 1, lsh + n + 1);
	for(int i = 1; i <= n; i++) {
		a[i] = lower_bound(lsh + 1, lsh + n + 1, a[i]) - lsh;
		mn[i] = mn2[i] = inf; mx[i] = mx2[i] = -inf;
	}
	scanf("%d", &q);
	for(int i = 1; i <= q; i++) {
		scanf("%d%d", &que[i].l, &que[i].r);
		que[i].askid = i;
	}
	sort(que + 1, que + q + 1);
	int nwl = 0, nwr = 0; nwans = 0;
	for(int k = 1; k <= q; k++) {
		int l = que[k].l, r = que[k].r; ans = 0;
		if(id[l] == id[r]) {
			for(int i = l; i <= r; i++) update3(i);
			res[que[k].askid] = ans;
			for(int i = l; i <= r; i++) 
				mx2[a[i]] = -inf, mn2[a[i]] = inf;
		} else {
			if(nwl != id[l] * B + 1) {
				nwl = id[l] * B + 1; nwr = r; nwans = 0;
				for(int i = 1; i <= n; i++) mx[i] = -inf, mn[i] = inf;
				for(int i = nwl; i <= nwr; i++) update(i);
			}
			while(nwr < r) update(++nwr);
			ans = nwans;
			for(int i = nwl - 1; i >= l; i--) update2(i);
			res[que[k].askid] = ans;
			for(int i = nwl - 1; i >= l; i--) mx2[a[i]] = -inf, mn2[a[i]] = inf;
		}
	}
	for(int i = 1; i <= q; i++) printf("%d\n", res[i]);
	return 0;
}

二次离线莫队

const int N = 1e5 + 10;
int n, m, k, B, pos[N], a[N], gs[N];
ll res[N], pre[N], tmp[N], cnt[(1 << 14) + 5];
vector<int>bz;
struct ques {
	int l, r, id;
	bool operator < (const ques x) const {
		return (pos[l] == pos[x.l]) ? r < x.r : pos[l] < pos[x.l];
	}
}q[N];
struct node {
	int l, r, tp, id;
	node(){}
	node(int aa, int b, int c, int d) {
		l = aa; r = b; tp = c; id = d; 
	}
};
vector<node>Q[N];
void init() {
	scanf("%d%d%d", &n, &m, &k); B = sqrt(n) + 1;
	for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
	for(int i = 0; i < (1 << 14); i++) {
		if(i) gs[i] = gs[i >> 1] + (i & 1);
		if(gs[i] == k) bz.push_back(i);
	}
//	for(int j = 0; j < (int)bz.size(); j++)
//		cout<<bz[j]<<"*\n";
//	puts("");
	memset(cnt, 0, sizeof(cnt));
	for(int i = 1; i <= n; i++) {
		pre[i] = cnt[a[i]];
		//cout<<pre[i]<<endl;
		for(int j = 0; j < (int)bz.size(); j++)
			cnt[bz[j] ^ a[i]]++;
	}
}
void solve() {
	for(int i = 1; i <= n; i++) pos[i] = (i - 1) / B + 1;
	for(int i = 1; i <= m; i++) scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
	sort(q + 1, q + m + 1);
	int l = 1, r = 0;
	for(int i = 1; i <= m; i++) {
		if(r < q[i].r) Q[l - 1].push_back(node(r + 1, q[i].r, -1, i));
		while(r < q[i].r) tmp[i] += pre[++r];
		if(l > q[i].l) Q[r].push_back(node(q[i].l, l - 1, 1, i));
		while(l > q[i].l) tmp[i] -= pre[--l];
		if(r > q[i].r) Q[l - 1].push_back(node(q[i].r + 1, r, 1, i));
		while(r > q[i].r) tmp[i] -= pre[r--];
		if(l < q[i].l) Q[r].push_back(node(l, q[i].l - 1, -1, i));
		while(l < q[i].l) tmp[i] += pre[l++];
	}
	memset(cnt, 0, sizeof(cnt));
	for(int i = 1; i <= n; i++) {
		for(int j = 0; j < (int)bz.size(); j++) cnt[bz[j] ^ a[i]]++;
		for(int j = 0; j < (int)Q[i].size(); j++) {
		//	cout<<i<<": "<<Q[i][j].l<<" "<<Q[i][j].r<<" "<<Q[i][j].tp<<endl;
			ll ret = 0;
			for(int o = Q[i][j].l; o <= Q[i][j].r; o++) 
				ret += cnt[a[o]] - (k == 0 && o <= i);
			tmp[Q[i][j].id] += ret * Q[i][j].tp;
		//	cout<<Q[i][j].id<<": "<<ret * Q[i][j].tp<<endl;
		}
	}
	for(int i = 1; i <= m; i++) tmp[i] += tmp[i - 1], res[q[i].id] = tmp[i];
	for(int i = 1; i <= m; i++) printf("%lld\n", res[i]);
}
int main() {
	init(); solve();
	return 0;
}

线段树合并

const int lim = 17, N = 1e5 + 10, M = 4e6 + 10, zlim = 1e5;
int n, m, f[N][20], dep[N], rt[N], ans[N];
int mx[M], ls[M], rs[M], id[M];
int e, hd[N], to[N << 1], nxt[N << 1], cnt;
vector<int>vec[N];
void add(int u, int v) {
	to[++e] = v; nxt[e] = hd[u]; hd[u] = e;
}
void dfs(int u, int fa) {
//	cout<<"dfs: "<<u<<" "<<fa<<endl;
	f[u][0] = fa;
	dep[u] = dep[fa] + 1;
	for(int i = 1; i <= lim; i++)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fa) continue;
		dfs(v, u);
	}
	return;
}
int lca(int x, int y) {
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = lim; i >= 0; i--)
		if(dep[f[x][i]] >= dep[y])
			x = f[x][i];
	if(x == y) return x;
	for(int i = lim; i >= 0; i--)
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	return f[x][0];
}
void pushup(int x) {
//	cout<<x<<" "<<ls[x]<<" "<<rs[x]<<endl;
	if(mx[ls[x]] >= mx[rs[x]])
		mx[x] = mx[ls[x]], id[x] = id[ls[x]];//, cout<<"pushup: "<<x<<" l"<<endl;
	else mx[x] = mx[rs[x]], id[x] = id[rs[x]];//, cout<<"pushup: "<<x<<" r"<<endl;
	return;
}
void update(int &x, int l, int r, int pos, int val) {
	if(!x) x = ++cnt;
//	cout<<"update: "<<x<<" "<<l<<" "<<r<<" "<<pos<<" "<<val<<endl;
	if(l == r) {
		mx[x] += val;
		if(mx[x] == 0) id[x] = 0;
		else id[x] = l; 
		//cout<<x<<": "<<l<<"~"<<r<<" val: "<<val<<": "<<mx[x]<<" "<<id[x]<<endl;
		return;
	}
	int mid = (l + r) >> 1;
	if(pos <= mid) update(ls[x], l, mid, pos, val);
	else update(rs[x], mid + 1, r, pos, val);
	pushup(x);
//	cout<<l<<"~"<<r<<": "<<mx[x]<<" "<<id[x]<<endl;
}
int merge(int x, int y, int l, int r) {
	if(!x || !y) return x | y;
	if(l == r) {
		mx[x] += mx[y];
		if(mx[x] == 0) id[x] = 0;
		else id[x] = l;
		return x;
	}
	int mid = (l + r) >> 1;
	ls[x] = merge(ls[x], ls[y], l, mid);
	rs[x] = merge(rs[x], rs[y], mid + 1, r);
	pushup(x);
	return x;
}
void solve(int u, int fa) {
//	cout<<"solve: "<<u<<" "<<fa<<endl;
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fa) continue;
		solve(v, u);
		merge(rt[u], rt[v], 1, zlim);
	}
	for(int i = 0; i < vec[u].size(); i++) {
		int x = vec[u][i];
		//cout<<"add: "<<u<<": "<<x<<endl;
		if(x > 0) update(rt[u], 1, zlim, x, 1);
		else update(rt[u], 1, zlim, -x, -1);
	}
//	cout<<"ans "<<u<<": "<<id[1]<<" "<<mx[1]<<endl;
	ans[u] = id[rt[u]];
	return; 
}
int main() {
//    freopen("ex.in", "r", stdin);
//    freopen("ex.out", "w", stdout);
	rd(n); rd(m);
	for(int i = 1, u, v; i < n; i++) {
		rd(u); rd(v);
		add(u, v); add(v, u);
	}
	cnt = n + 1;
	for(int i = 1; i <= n; i++)
		rt[i] = i;
	dfs(1, 0);
	for(int i = 1, x, y, z; i <= m; i++) {
		rd(x); rd(y); rd(z);
		vec[x].push_back(z);
		vec[y].push_back(z);
		int t = lca(x, y);
		vec[t].push_back(-z);
		vec[f[t][0]].push_back(-z);
	}
	solve(1, 0);
	for(int i = 1; i <= n; i++)
		printf("%d\n", ans[i]);
    return 0;
}

树套树

const int N = 1e5 + 10, inf = 2147483647;
int n, m, stval[N];
namespace Treap {
	int tot = 0;
	struct node {
		int pri, val, sz, ch[2];
		node(){}
		node(int a, int b, int c, int d, int e) {
			pri = a; val = b; sz = c; ch[0] = d; ch[1] = e;
		}
	}tr[N << 5];//?
	inline void pushup(int p) {
		tr[p].sz = tr[tr[p].ch[0]].sz + tr[tr[p].ch[1]].sz + 1;
	}
	inline void split(int p, int w, int &x, int &y) {
	//	cout<<"split: "<<p<<" "<<w<<endl;
	//	cout<<p<<" "<<tr[p].val<<endl;
	//	cout<<tr[p].ch[0]<<" "<<tr[tr[p].ch[0]].val<<endl;
	//	cout<<tr[p].ch[1]<<" "<<tr[tr[p].ch[1]].val<<endl;
		if(!p) return x = y = 0, void();
		if(tr[p].val <= w) {
			x = p; split(tr[p].ch[1], w, tr[x].ch[1], y);
		} else {
			y = p; split(tr[p].ch[0], w, x, tr[y].ch[0]);
		}
		pushup(p);
	}
	inline 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;
		}
	}
	inline int newnode(int w) {
		tr[++tot] = node(rand(), w, 1, 0, 0);
		return tot;
	}
	inline void ins(int &p, int w) {
	//	cout<<"ins: "<<p<<" "<<w<<endl;
		int x, y; split(p, w, x, y);
	//	cout<<"split: "<<x<<" "<<y<<endl;
		p = merge(x, merge(newnode(w), y));
	}
	inline void del(int &p, int w) {
		int x, y, z; split(p, w, x, z);
		split(x, w - 1, x, y);
		y = merge(tr[y].ch[0], tr[y].ch[1]);
		p = merge(x, merge(y, z));
	}
	inline int query_rk(int p, int k) {
	//	cout<<p<<" "<<k<<endl;
		int x, y; split(p, k - 1, x, y);
		int ret = tr[x].sz;
		p = merge(x, y);
		return ret;
	}
	inline int query_kth(int p, int k) {
		int l = tr[p].ch[0], r = tr[p].ch[1];
		if(tr[l].sz >= k) return query_kth(l, k);
		else if(tr[l].sz + 1 == k) return tr[p].val;
		else return query_kth(r, k - 1 - tr[l].sz);
	}
	inline int query_pre(int p, int k) {
		int x, y; split(p, k - 1, x, y);
		int ret = -inf;
		if(tr[x].sz) ret = query_kth(x, tr[x].sz);
		p = merge(x, y);
		return ret;
	}
	inline int query_nxt(int p, int k) {
		int x, y; split(p, k, x, y);
		int ret = inf;
		if(tr[y].sz) ret = query_kth(y, 1);
		p = merge(x, y);
		return ret;
	}
}
namespace ST {
	int tr[N << 2]; //所代表平衡树的根节点标号。
	inline void build(int p, int l, int r) {
	//	cout<<"build: "<<p<<" "<<l<<" "<<r<<endl;
		for(int i = l; i <= r; i++)
			Treap::ins(tr[p], stval[i]);
		if(l == r) return;
		int mid = (l + r) >> 1;
		build(ls(p), l, mid);
		build(rs(p), mid + 1, r);
	}
	inline void modify(int p, int l, int r, int pos, int k) {
	//	cout<<"modify: "<<p<<" "<<l<<" "<<r<<" "<<pos<<" "<<k<<endl;
		Treap::del(tr[p], stval[pos]); Treap::ins(tr[p], k);
		if(l == r) return;
		int mid = (l + r) >> 1;
		if(pos <= mid) modify(ls(p), l, mid, pos, k);
		else modify(rs(p), mid + 1, r, pos, k);
	}
	inline int query_rk(int p, int l, int r, int L, int R, int k) {
	//	cout<<"query_rk: "<<p<<" "<<l<<" "<<r<<" "<<L<<" "<<" "<<R<<" "<<k<<endl;
		if(L <= l && r <= R) {
		//	cout<<l<<" "<<r<<" k: "<<k<<endl;
			int ret = Treap::query_rk(tr[p], k);
		//	cout<<l<<" "<<r<<" ret: "<<ret<<endl;
			return ret;
		}
		int mid = (l + r) >> 1, ret = 0;
		if(L <= mid) ret += query_rk(ls(p), l, mid, L, R, k);
		if(R > mid) ret += query_rk(rs(p), mid + 1, r, L, R, k);
		return ret;
	}
	inline int query_kth(int L, int R, int k) {
		int l = 0, r = 1e8, bst = 0;
		while(l <= r) {
			int mid = (l + r) >> 1;
			int tmp = query_rk(1, 1, n, L, R, mid) + 1;
		//	cout<<"check: "<<mid<<" "<<tmp<<endl;
			if(tmp <= k) bst = mid, l = mid + 1;
			else r = mid - 1;
		}
		return bst;
	}
	inline int query_pre(int p, int l, int r, int L, int R, int k) {
		if(L <= l && r <= R) return Treap::query_pre(tr[p], k);
		int mid = (l + r) >> 1, ret = -inf;
		if(L <= mid) ret = max(ret, query_pre(ls(p), l, mid, L, R, k));
		if(R > mid) ret = max(ret, query_pre(rs(p), mid + 1, r, L, R, k));
		return ret;
	}
	inline int query_nxt(int p, int l, int r, int L, int R, int k) {
		if(L <= l && r <= R) return Treap::query_nxt(tr[p], k);
		int mid = (l + r) >> 1, ret = inf;
		if(L <= mid) ret = min(ret, query_nxt(ls(p), l, mid, L, R, k));
		if(R > mid) ret = min(ret, query_nxt(rs(p), mid + 1, r, L, R, k));
		return ret;
	}
}
inline int rd() {
	int num = 0;
	char c = getchar(); bool f = 0;
	while(c < '0' || c > '9') {
		if(c == '-') f = 1;
		c = getchar();	
	}
	while(c >= '0' && c <= '9') {
		num = (num << 3) + (num << 1) + (c & 15);
		c = getchar();	
	}
	return f ? -num : num;
}
int main() {
//	freopen("ex.in", "r", stdin);
//	freopen("ex.out", "w", stdout);
	srand(time(0));
	n = rd(); m = rd();
	for(int i = 1; i <= n; i++) stval[i] = rd();
//	cout<<"what is tree tree"<<endl;
	ST::build(1, 1, n);
	for(int i = 1, opt, pos, k, l, r; i <= m; i++) {
		opt = rd();
		if(opt == 3) pos = rd(), k = rd(), ST::modify(1, 1, n, pos, k), stval[pos] = k;
		else {
			l = rd(); r = rd(); k = rd();
			if(opt == 1) printf("%d\n", ST::query_rk(1, 1, n, l, r, k) + 1);
			else if(opt == 2) printf("%d\n", ST::query_kth(l, r, k));
			else if(opt == 4) printf("%d\n", ST::query_pre(1, 1, n, l, r, k));
			else printf("%d\n", ST::query_nxt(1, 1, n, l, r, k));
		}
	}
	return 0;
}
/*
9 1
4 2 2 1 9 4 0 1 1
2 1 4 3
*/

LCT

const int N=3e5+10;
int n,m;
int c[N][2],f[N],s[N],v[N],r[N],st[N];
inline bool nroot(int x){
	return (c[f[x]][0]==x||c[f[x]][1]==x);
}
void pushup(int x){
	s[x]=s[c[x][0]]^s[c[x][1]]^v[x];
}
void pushr(int x){
	swap(c[x][0],c[x][1]); r[x]^=1;
}
void pushdown(int x){
	if(r[x]){
		if(c[x][0]) pushr(c[x][0]);
		if(c[x][1]) pushr(c[x][1]);
		r[x]=0;
	}
}
void rotate(int x){
	int y=f[x],z=f[y],k=(c[y][1]==x),w=c[x][k^1];
	if(nroot(y)) c[z][(c[z][1]==y)]=x; c[y][k]=w; c[x][k^1]=y; 
	if(w) f[w]=y; f[y]=x; f[x]=z;
	pushup(y);//可以不更新,会在下一次rotate中更新
	return;
}
void splay(int x){//目标为根
	int y=x,z=0;
	st[++z]=y; while(nroot(y)) y=f[y],st[++z]=y;
	while(z) pushdown(st[z--]);
	while(nroot(x)){
		y=f[x];z=f[y];
		if(nroot(y))
			rotate(((c[y][0]==x)^(c[z][0]==y))?x:y);
		rotate(x);
	}
	pushup(x);
}
void access(int x){
	for(int y=0;x;y=x,x=f[x])
		splay(x),c[x][1]=y,pushup(x);
}
void makeroot(int x){
	access(x); splay(x); pushr(x);
}
int findroot(int x){
	access(x); splay(x);
	while(c[x][0]) pushdown(x),x=c[x][0];
	splay(x);
	return x;
}
void split(int x,int y){
	makeroot(x); access(y); splay(y);
}
void link(int x,int y){
	makeroot(x); if(findroot(y)!=x) f[x]=y;
}
void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&f[y]==x&&!c[y][0]){
		f[y]=c[x][1]=0;
		pushup(x);
	}
}
int main(){
	n=read(); m=read();
	for(int i=1;i<=n;i++) v[i]=read();
	while(m--){
		int tp=read(),x=read(),y=read();
		switch(tp){
			case 0: split(x,y); printf("%d\n",s[y]); break;
			case 1: link(x,y); break;
			case 2: cut(x,y); break;
			case 3: splay(x); v[x]=y;
		}
	}
	return 0;
}

线段树分治

const int N = 1e5 + 10, M = 2e5 + 10;
int n, m, k, f[N << 1], sz[N << 1], top;
PII ed[M], op[M];
vector<int>vec[N << 2];
void update(int rt, int l, int r, int L, int R, int val) {
    if(L <= l && r <= R) {
        vec[rt].push_back(val);
        return;
    }
    int mid = (l + r) >> 1;
    if(L <= mid) update(ls(rt), l, mid, L, R, val);
    if(R > mid) update(rs(rt), mid + 1, r, L, R, val);
}
int find(int x) {
    return (x == f[x]) ? x : find(f[x]);
}
void merge(int x, int y) {
    x = find(x); y = find(y);
    if(sz[x] > sz[y]) swap(x, y);
    //cout<<"merge: "<<x<<" "<<y<<endl;
    op[++top] = mkp(x, y);
    f[x] = y; sz[y] += sz[x];
}
void solve(int rt, int l, int r) {
    //cout<<"solve: "<<rt<<" "<<l<<" "<<r<<endl;
    int nwtop = top;
    bool fl = 1;
    for(int i = 0; i < (int)vec[rt].size(); i++) {
        PII qwq = ed[vec[rt][i]];
        if(find(qwq.fi) == find(qwq.se)) {
            fl = 0;
            for(int i = l; i <= r; i++)
                puts("No");
            break;
        }
        merge(qwq.fi, qwq.se + n);
        merge(qwq.se, qwq.fi + n);
    }
    if(fl) {
        if(l == r) puts("Yes");
        else {
            int mid = (l + r) >> 1;
            solve(ls(rt), l, mid);
            solve(rs(rt), mid + 1, r);
        }
    }
    while(top > nwtop) {
        int x = op[top].fi, y = op[top].se;
        sz[y] -= sz[x]; f[x] = x;
        top--;
    }
}
int main() {
   // freopen("ex.in", "r", stdin);
   // freopen("password.out", "w", stdout);
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1, l, r; i <= m; i++) {
        scanf("%d%d%d%d", &ed[i].fi, &ed[i].se, &l, &r);
        if(l + 1 <= r) update(1, 1, k, l + 1, r, i);
    }
    for(int i = 1; i <= 2 * n; i++) f[i] = i, sz[i] = 1;
    solve(1, 1, k);
    return 0;
}

网络流

二分图最大匹配

int n, m, k, vis[N], pp[N];
bool mp[N][N];
bool dfs(int u) {
	for(int v = 1; v <= m; v++) {
		if(!vis[v] && mp[u][v]) {
			vis[v] = 1;
			if(!pp[v] || dfs(pp[v])) {
				pp[v] = u;
				return 1;
			}
		}
	}
	return 0;
}
int hungary() {
	int ans = 0;
	for(int i = 1; i <= n; i++) {
		memset(vis, 0, sizeof(vis));
		ans += dfs(i);	
	}
	return ans;
}

最大流

const int N = 210, M = 5010;
int n, m, s, t;
int e, to[M << 1], val[M << 1], nxt[M << 1], hd[N], cur[N], dep[N];
void add(int u, int v, int w) {
	to[++e] = v; val[e] = w;
	nxt[e] = hd[u]; hd[u] = e;
} 
ll inf = 1e18;
bool bfs() {
	queue<int>q; 
	for(int i = 1; i <= n; i++)
		dep[i] = -1, cur[i] = hd[i];
	dep[s] = 0; q.push(s);
	while(!q.empty()) {
		int u = q.front(); q.pop();
		for(int i = hd[u]; i; i = nxt[i]) {
			int v = to[i];
			if(dep[v] == -1 && val[i] > 0) {
				dep[v] = dep[u] + 1;
				q.push(v);
			}
		}
	}
	return dep[t] != -1;
}
ll dfs(int u, ll flow) {
	if(u == t) return flow;
	ll usd = 0;
	for(int &i = cur[u]; i; i = nxt[i]) {//!
		int v = to[i]; 
		if(dep[v] == dep[u] + 1 && val[i] > 0) {
			ll t = dfs(v, min(flow - usd, (ll)val[i]));
			val[i] -= t;
			val[i ^ 1] += t;
			usd += t;
		}
		if(flow == usd) break;
	}
	return usd;
}
ll dinic() {
	ll flow = 0;
	while(bfs())
		flow += dfs(s, inf);
	return flow;
}
int main() {
	rd(n); rd(m); rd(s); rd(t);
	e = 1;
	for(int i = 1, u, v, w; i <= m; i++) {
		rd(u); rd(v); rd(w);
		add(u, v, w); add(v, u, 0);
	}
	printf("%lld\n", dinic());
    return 0;
}

最小费用最大流

const int N = 5e3 + 10, M = 5e4 + 10, inf  = 0x3f3f3f3f;
int n, m, s, t, dist[N], pre[N], inq[N];
int e = 1, hd[N], to[M << 1], nxt[M << 1], fval[M << 1], cval[M << 1];
void add(int u, int v, int w, int c) {
	to[++e] = v; nxt[e] = hd[u];
	fval[e] = w; cval[e] = c;
	hd[u] = e;
} 
bool spfa() {
	for(int i = 1; i <= n; i++)
		dist[i] = inf, pre[i] = 0;
	queue<int>q;
	inq[s] = 1; q.push(s); dist[s] = 0;
	while(!q.empty()) {
		int u = q.front(); q.pop(); inq[u] = 0;
		for(int i = hd[u]; i; i = nxt[i]) {
			int v = to[i];
			if(fval[i] > 0 && dist[v] > dist[u] + cval[i]) {
				dist[v] = dist[u] + cval[i]; pre[v] = i;
				if(!inq[v]) inq[v] = 1, q.push(v);
			}
		}
	}
	return dist[t] != inf;
}
void update(ll &fflow, ll &cflow) {
	int mi = inf;
	for(int i = pre[t]; i; i = pre[to[i ^ 1]]) {
		mi = min(mi, fval[i]);
	}
	fflow += mi;
	for(int i = pre[t]; i; i = pre[to[i ^ 1]]) {
		fval[i] -= mi; fval[i ^ 1] += mi;
		cflow += mi * cval[i];
	}
	return;
}
void SSP() {
	ll fflow = 0, cflow = 0;
	while(spfa()) update(fflow, cflow);
	printf("%lld %lld\n", fflow, cflow);
	return;
}
int main() {
	rd(n); rd(m); rd(s); rd(t);
	for(int i = 1, u, v, w, c; i <= m; i++) {
		rd(u); rd(v); rd(w); rd(c);
		add(u, v, w, c); add(v, u, 0, -c);
	}
	SSP();
    return 0;
}

数论与数学

逆元

//线性求逆元 mod为质数
iv[0] = iv[1] = 1;
for(int i = 2; i <= n; i++)
	iv[i] = (ll)iv[mod % i] * (mod - mod / i) % mod;

exgcd

int exgcd(int a, int b, ll &x, ll &y) {
	if(b == 0) {
		x = 1; y = 0;
		return a;
	}
	int t = exgcd(b, a % b, y, x); 
	y -= a / b * x;
	return t;
} 
void solve(int a, int b, int c) {
	ll x, y;
	int g = exgcd(a, b, x, y);
	if(c % g) return puts("-1"), void();
	x *= (c / g); y *= (c / g);
	ll mnx, mny, mxx, mxy;
	mnx = ((x - 1) % (b / g) + (b / g)) % (b / g) + 1;
	mxy = (c - a * mnx) / b;
	if(mnx > 0 && mxy > 0) {
		mny = ((y - 1) % (a / g) + (a / g)) % (a / g) + 1;
		mxx = (c - b * mny) / a;
		printf("%lld %lld %lld %lld %lld\n", (mxx - mnx) / (b / g) + 1, mnx, mny, mxx, mxy);
	} else {
		x = ((x - 1) % (b / g) + (b / g)) % (b / g) + 1;
		y = ((y - 1) % (a / g) + (a / g)) % (a / g) + 1;
		printf("%lld %lld\n", x, y);
	}
	return;
}
int main() {
	//freopen("ex.in", "r", stdin);
	int T; scanf("%d", &T);
	while(T--) {
		int a, b, c; scanf("%d%d%d", &a, &b, &c);
		solve(a, b, c);
	} 
	return 0;
}
/*
若该方程无整数解,输出 -1
若该方程有整数解,且有正整数解,
则输出其正整数解的数量,所有正整数解中 x 的最小值,所有正整数解中 y 的最小值,
所有正整数解中 xx 的最大值,以及所有正整数解中 yy 的最大值。

若方程有整数解,但没有正整数解,你需要输出所有整数解中 x 的最小正整数值, y 的最小正整数值。

正整数解即为 x, yx,y 均为正整数的解
整数解即为 x,yx,y 均为整数的解。
x 的最小正整数值即所有 x 为正整数的整数解中 x 的最小值,y 同理。
*/

线性筛素数

bool vis[N];
int pr[M], cnt; 
void init() {
	vis[1] = 1;
	for(int i = 2; i <= 100000000; i++) {
		if(!vis[i]) pr[++cnt] = i;
		for(int j = 1; j <= cnt && pr[j] * i <= 100000000; j++) {
			vis[pr[j] * i] = 1;
			if(i % pr[j] == 0) break;  
		}		
	}
	return;
}

康托展开

for(int i = 1, x; i <= n; i++) {
	scanf("%d", &x);
	insert(x, 1);
	(ans += (ll)fac[n - i] * (x - 1 - query(x - 1)) % mod) %= mod; //比我小还在我后面。 
}
printf("%d\n", ans + 1);	

拉格朗日插值

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+10,mod=998244353;
int x[N],y[N];
inline int read(){
    int num=0,fff=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') fff=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        num=(num<<3)+(num<<1)+ch-'0';
        ch=getchar();
    }
    return num*fff;
}
inline int power(int a,int b){
    int ret=1;
    while(b){
        if(b&1) ret=1ll*ret*a%mod;
        a=1ll*a*a%mod; b>>=1;
    }
    return ret;
}
inline int inv(int x){ return power(x,mod-2); }
int main(){
    int n,k; n=read(); k=read();
    for(int i=1;i<=n;i++)
        x[i]=read(),y[i]=read();
    int ans=0;
    for(int i=1;i<=n;i++){
        int ret=y[i],tmp=1;
        for(int j=1;j<=n;j++){
            if(j==i) continue;
            ret=1ll*ret*(k-x[j])%mod;
            tmp=1ll*tmp*(x[i]-x[j])%mod;
        }
        ret=1ll*ret*inv(tmp)%mod;
        ans=(ans+ret)%mod;
    }
    printf("%d\n",(ans+mod)%mod);
    return 0;
}

高斯消元法

double a[105][105];
int main() {
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n + 1; j++)
			scanf("%lf", &a[i][j]); 
	for(int i = 1; i <= n; i++) {
		int id = i;
		for(int j = i + 1; j <= n; j++)
			if(a[j][i]) id = j;
		if(id != i) {
			for(int j = 1; j <= n + 1; j++)
				swap(a[id][j], a[i][j]);
		}
		if(!a[i][i]) return puts("No Solution"), 0;
		for(int j = 1; j <= n; j++) {
			if(j == i) continue;
			double t = a[j][i] / a[i][i];
			for(int k = 1; k <= n + 1; k++)
				a[j][k] -= t * a[i][k];
		}
	}
	for(int i = 1; i <= n; i++)
		printf("%.2lf\n", a[i][n + 1] / a[i][i]);
	return 0;
}

中国剩余定理 CRT

const int N = 15;
int n, a[N], b[N];
void exgcd(ll a, ll b, ll &x, ll &y, ll &d) {
	if(b == 0) x = 1, y = 0, d = a;
	else exgcd(b, a % b, y, x, d), y = y - a / b * x;
	return;
}
ll gcd(ll x, ll y) {
	return (y == 0) ? x : gcd(y, x % y);	
}
int main(){
	scanf("%d", &n);
	ll M = 1;
	for(int i = 1; i <= n; i++) {
		scanf("%d%d", &a[i], &b[i]);
		M = M * a[i] / gcd(a[i], M);
	}
	ll ans = 0;
	for(int i = 1; i <= n; i++) {
		ll x, y, d, m = M / a[i]; exgcd(m, a[i], x, y, d);
		x = (x % a[i] + a[i]) % a[i];
		ans = (ans + 1ll * b[i] * m % M * x % M) % M;
	}
	printf("%lld\n", ans);
	return 0;
}

exCRT

ll n, a[100010], b[100010];
ll exgcd(ll a, ll b, ll &x, ll &y) {
	if(b == 0) {
		x = 1; y = 0; return a;
	}
	ll t = exgcd(b, a % b, y, x);
	y -= a / b * x;
	return t;
}
ll mul(ll x, ll y, ll mod) {
//	cout<<"mul: "<<x<<" "<<y<<endl;
	x = x % mod; y = y % mod;
	ll ret = 0;
	while(y) {
	//	cout<<"ret: "<<ret<<" y: "<<y<<endl;
		if(y & 1) {
			ret += x; if(ret >= mod) ret -= mod;
		}
		y >>= 1; x += x; if(x >= mod) x -= mod;
	}
	return ret;
}
int main() {
	scanf("%lld", &n);
	ll lcm = 1, ans = 0;
	for(int i = 1; i <= n; i++) {
		scanf("%lld%lld", &a[i], &b[i]);
		//ans[k]=ans[k-1]+x*lcm  % a[i] = b[i] 
		//x*lcm  + a[i] * y = b[i]-ans[k-1]
		ll C = (b[i] % a[i] + a[i] - ans % a[i]) %  a[i];
		ll x, y;
		ll g = exgcd(lcm, a[i], x, y);
		x = (x % (a[i] / g) + (a[i] / g)) % (a[i] / g);
		x = mul(x, C / g, a[i]);
		ll nwlcm = lcm / g * a[i];
		ans = (ans + mul(x, lcm, nwlcm)) % nwlcm;
		lcm = nwlcm;
	}
	printf("%lld\n", ans);
	return 0;
}

扩展欧拉定理

const int N = 2e7 + 10, M = 1e8; 
char s[N];
int calc(int x) {
	int ret = x;
	for(int i = 2; i * i <= x; i++) {
		if(x % i == 0) ret /= i, ret *= (i - 1);
		while(x % i == 0) x /= i;
	}
	if(x != 1) ret /= x, ret *= (x - 1);
	return ret;
}
int power(int a, int b, int mod) {
	int ret = 1;
	while(b) {
		if(b & 1) ret = 1ll * ret * a % mod;
		a = 1ll * a * a % mod; b >>= 1;
	}
	return ret;
}
int main(){
	int a, b = 0, m;
	scanf("%d%d%s", &a, &m, s + 1);
	int t = calc(m);
	int len = strlen(s + 1);
	bool fl = 0;
	for(int i = 1; i <= len; i++) {
		b = b * 10 + s[i] - '0';
		if(b >= t) fl = 1; 
		b %= t;
	}
	if(b == 0) printf("%d\n", power(a, t, m));
	else if(fl) printf("%d\n", power(a, b, m));
	else printf("%d\n", power(a, b, m));
	return 0;
}

卢卡斯

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll quick_pow(ll a,ll b,ll p){
	ll ret=1;
	a%=p;
	while(b){
		if(b&1) ret=(ret*a)%p;
		b/=2;
		a=(a*a)%p; 
	}
	ret%=p;
	return ret;
}
ll inv(ll x,ll p) {
	return quick_pow(x,p-2,p);
}
ll c(ll n,ll m,ll p) {
	if(m>n) return 0;
	ll up=1,down=1;
	for(ll i=n-m+1; i<=n; i++) up=up*i%p;
	for(ll i=1; i<=m; i++) down=down*i%p;
	return up*inv(down,p)%p;
}
ll Lucas(ll n,ll m,ll p) {
	if(m==0) return 1;
	return c(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;
}
int main() {
	ll t,n,m,p;
	scanf("%lld",&t);
	while(t--) {
		scanf("%lld%lld%lld",&n,&m,&p);n+=m;
		printf("%lld\n",Lucas(n,m,p));
	}
	return 0;
}

扩展Lucas

const LL N=15;
LL k,ai[N],bi[N],pi[N],tot[N];
LL exgcd(LL a,LL b,LL &x,LL &y){
    if(!b){ x=1,y=0;return a; }
    LL gcd=exgcd(b,a%b,y,x);y-=a/b*x;
    return gcd;
}
LL inv(LL v,LL mod){
    LL  x,y;
    exgcd(v,mod,x,y);
    return (x%mod+mod)%mod;
}

LL mul(LL a,LL b,LL mod){
    LL ret=0;
    while(b){
        if(b&1) ret=(ret+a)%mod;
        b>>=1;a=(a+a)%mod;
    }
    return (ret+mod)%mod;
}
LL power(LL a,LL b,LL mod){
    LL ret=1;
    while(b){
        if(b&1) ret=ret*a%mod;
        a=a*a%mod;b>>=1; 
    }
    return (ret+mod)%mod;
}

LL calc(LL r,LL p,LL mod){
    LL ret=1;
    for(LL i=1;i<=r;i++)
        if(i%p) ret=ret*(i%mod)%mod;
    return (ret+mod)%mod;
}
inline LL f(LL n,LL p,LL pk){
    if(n==0) return 1;
    return (f(n/p,p,pk)%pk * power( calc(pk,p,pk) , n/pk , pk ) % pk  * calc( n%pk,p,pk )%pk+pk )%pk;
}//1-n中非p因子的乘积
inline LL g(LL n,LL p){
    if(n<p) return 0;
    return n/p+g(n/p,p);
}//计算p因子个数

LL excrt(){
    LL x,y,M=1,ans=0;
    for(LL i=1;i<=k;i++){
        LL a=M,b=ai[i],c=((bi[i]-ans)%ai[i]+ai[i])%ai[i];
        LL gcd=exgcd(a,b,x,y),ag=ai[i]/gcd;
        if(c%gcd) return -1;//扩欧有解条件
        x=mul(x,c/gcd,ag);//x*(c/gcd)%ag
        ans+=x*M;M*=ag;
        ans=(ans+M)%M;
    }
    return ans;
}
LL exLucas(LL n,LL m,LL p){
    k=0;
    for(LL i=2;i*i<=p;i++){
        if(p%i==0){
            ++k;pi[k]=i;ai[k]=1;
            while(p%i==0) p/=i,ai[k]*=i,tot[k]++;
        }
    }
    //计算bi
    if(p!=1){
        ++k;pi[k]=p;ai[k]=p;tot[k]=1;
    }
    for(LL i=1;i<=k;i++){
        LL tmpp= g(n,pi[i]) - g(m,pi[i]) - g(n-m,pi[i]);
        bi[i]= f(n,pi[i],ai[i])%ai[i] * inv( f(m,pi[i],ai[i]) ,ai[i] ) %ai[i] * inv( f(n-m,pi[i],ai[i]) ,ai[i] ) %ai[i] 
                    *power( pi[i], tmpp , ai[i] )%ai[i];
     //   cout<<ai[i]<<" "<<bi[i]<<endl;
    }
    return excrt();
}

int main(){
    LL n,m,p;
    scanf("%lld%lld%lld",&n,&m,&p);
    printf("%lld\n",exLucas(n,m,p));
    return 0;
}

BSGS

map<int, int>mp;
int main() {
	int p, b, n;
	scanf("%d%d%d", &p, &b, &n);
	int B = sqrt(p - 1) + 1, s = 1;
	for(int i = 0; i < B; i++)
		mp[(ll)s * n % p] = i, s = (ll)s * b % p;
	mp[(ll)s * n % p] = B;
	int tmp = s;
	for(int i = 1; i <= ((p - 1) - 1) / B + 1; i++) {
	//	cout<<"tmp: "<<tmp<<endl;
		if(mp.find(tmp) != mp.end())
			return printf("%d\n", i * B - mp[tmp]), 0;
		tmp = (ll)tmp * s % p;
	}
	puts("no solution");
	return 0;
}

扩展BSGS

void exgcd(ll a, ll b, ll &x, ll &y) {
    if(b == 0) {
        x = 1; y = 0;
    } else {
        exgcd(b, a % b, y, x); 
        y -= a / b * x;
    }
}
map<ll, ll>mp;
ll bsgs(ll a, ll p, ll b) {
    mp.clear();
    ll B = ceil(sqrt(p));
    ll s = 1;
    for(ll i = 0; i < B; i++) {
        mp[s * b % p] = i;
        s = s * a % p;
    }
    ll sum = 1;
    for(ll i = 1; i <= (p - 1) / B + 1; i++) {
        sum = sum * s % p;
        if(mp.find(sum) != mp.end())
            return i * B - mp[sum];
    }
    return -1;
}
ll exbsgs(ll a, ll p, ll b) {
    a %= p; b %= p;
    if(b == 1 || p == 1) return 0;
    ll cnt = 0;
    ll d = __gcd(a, p), aa = 1;
    while(d != 1) {
        if(b % d) return -1;
        b /= d; p /= d; aa = aa * (a / d) % p;
        d = __gcd(a, p);
        cnt++;
        if(aa == b) return cnt;
    }
    //a^{x-cnt}= (b / a^cnt)  mod p
    ll ivak, y; exgcd(aa, p, ivak, y);
    ivak = (ivak % p + p) % p;
    ll ans = bsgs(a, p, b % p * ivak % p);
    return (ans == -1) ? -1 : ans + cnt;
}
int main() {
   ll a, p, b;
   while(scanf("%lld%lld%lld", &a, &p, &b) != EOF && a && p && b) {
       ll ans = exbsgs(a, p, b);
       if(ans == -1) puts("No Solution");
        else printf("%lld\n", ans);
   }
    return 0;
}

线性基

const int N=55;
int n;
ll p[N];
void insert(ll x){
    for(int i=50;i>=0;i--)
        if(x&(1ll<<i)){
            if(!p[i]){ p[i]=x; break; }
            else x^=p[i];
        }
    return;
}
ll query(){
    ll ret=0;
    for(int i=50;i>=0;i--)
        if(!(ret&(1ll<<i))) ret^=p[i];
    return ret;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        ll x; scanf("%lld",&x); insert(x);
    }
    printf("%lld\n",query());
    return 0;
}

高斯消元法

double a[105][105];
int main() {
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n + 1; j++)
			scanf("%lf", &a[i][j]); 
	for(int i = 1; i <= n; i++) {
		int id = i;
		for(int j = i + 1; j <= n; j++)
			if(a[j][i]) id = j;
		if(id != i) {
			for(int j = 1; j <= n + 1; j++)
				swap(a[id][j], a[i][j]);
		}
		if(!a[i][i]) return puts("No Solution"), 0;
		for(int j = 1; j <= n; j++) {
			if(j == i) continue;
			double t = a[j][i] / a[i][i];
			for(int k = 1; k <= n + 1; k++)
				a[j][k] -= t * a[i][k];
		}
	}
	for(int i = 1; i <= n; i++)
		printf("%.2lf\n", a[i][n + 1] / a[i][i]);
	return 0;
}

杜教筛

typedef unsigned long long ull;
const int N=5e6+10;
bool vis[N];
int cnt,mu[N],phi[N],p[N];
ll summu[N],sumphi[N];
map<ll,ll>mpmu;
map<ll,ull>mpphi;
int bmin(ll x,ll y){ return (x>y)?y:x; }
void init(ll n){
	mu[1]=1; vis[1]=1; phi[1]=1;
	for(ll i=2;i<=n;i++){
		if(!vis[i]) p[++cnt]=i,mu[i]=-1,phi[i]=i-1;
		for(ll j=1;j<=cnt&&p[j]*i<=n;j++){
			vis[p[j]*i]=1;
			if(i%p[j]==0){
				phi[i*p[j]]=phi[i]*p[j];
				break;
			}
			mu[i*p[j]]=-mu[i];
			phi[i*p[j]]=phi[i]*(p[j]-1);
		}
	}
	for(ll i=1;i<=n;i++){
		summu[i]=summu[i-1]+mu[i];
		sumphi[i]=sumphi[i-1]+phi[i];
	}
	return;
}
ll getsummu(ll n){
	if(n<=N-10) return summu[n];
	else if(mpmu.count(n)) return mpmu[n];
	//杜教筛
	ll ret=1;
	for(ll l=2,r;l<=n;l=r+1){
		r=bmin(n,n/(n/l));
		ret-=getsummu(n/l)*(r-l+1);
	}
	return mpmu[n]=ret;
}
ull getsumphi(ll n){
	if(n<=N-10) return sumphi[n];
	else if(mpphi.count(n)) return mpphi[n];
	//杜教筛
	ull ret=1ll*n*(n+1)/2;
	for(ll l=2,r;l<=n;l=r+1){
		r=bmin(n,n/(n/l));
		ret-=(ull)getsumphi(n/l)*(r-l+1);
	}
	return mpphi[n]=ret;
}
int main(){
	int t; scanf("%d",&t);
	while(t--){
		ll n; scanf("%lld",&n);
		init(N-10);
		printf("%llu %lld\n",getsumphi(n),getsummu(n));
	}
	return 0;
}
/*
\sum_{d=1}^{n} \mu(d) \frac {(t-1)·(t-2)} 4 
mu: s(n)=1-\sum_{d=2}^n s(\lfloor \frac n d \rfloor)
*/

Pollard-Rho

ll power(ll a, ll b, ll p) {
	ll ret = 1;
	while(b) {
		if(b & 1) ret = (__int128)ret * a % p;
		a = (__int128)a * a % p; b >>= 1;
	}
	return ret;
}
bool check(ll a, ll u, ll t, ll n) {
//	cout<<"check: "<<a<<" "<<u<<" "<<t<<endl;
	ll b = power(a, u, n);
//	cout<<"b: "<<b<<endl;
	while(t--) {
	//	cout<<"b: "<<b<<endl;
		ll tmp = b;
		b = (__int128)b * b % n;
		if(tmp != 1 && tmp != n - 1 && b == 1) return 0;
		if(b == 1 || b == -1) return 1;
	}
	return (b == 1);
}
bool is_prime(ll n) { //Miller_Rabin
	if(n < 2) return 0;
	if(n == 2) return  1;
	if((n & 1) == 0) return 0;
	ll u = n - 1, t = 0;
	while(!(u & 1)) t++, u >>= 1;
//	cout<<u<<" "<<t<<endl;
	for(int i = 0; i < 8; i++) {
		ll a = 1ll * rand() * rand() % (n - 1) + 1;
		if(!check(a, u, t, n)) return 0;
	}
	return 1;
}
inline ll f(ll x, ll c, ll n) { return ((__int128)x * x + c) % n; }
ll Pollard_Rho(ll n) {
	if(n == 4) return 2;
	if(is_prime(n)) return n;
	while(1) {
		ll c = 1ll * rand() * rand() % (n - 1) + 1;
	//	cout<<"c: "<<c<<endl;
		ll t = 0, r = 0, p = 1; int gap = 128;
		do {
			for(int i = 0; i < gap; i++) {
				t = f(t, c, n), r = f(f(r, c, n), c, n);
				ll tmp = (__int128) p * abs(t - r) % n;
				if(t == r || tmp == 0) break;
				p = tmp;
			}
			ll d = __gcd(p, n);
			if(d > 1) return d;
		}while(t != r);
	}
}
map<ll, ll>vis;
ll max_prime_factor(ll n) {
	if(vis.count(n)) return vis[n];
	ll fac = Pollard_Rho(n);
	if(fac == n) return vis[n] = n;
	return vis[n] = max(max_prime_factor(n / fac), max_prime_factor(fac));
}
int main() {
	srand(time(0));
	int T;
	scanf("%d", &T);
	while(T--) {
		ll n;
		scanf("%lld", &n);
		if(is_prime(n)) printf("Prime\n");
		else printf("%lld\n", max_prime_factor(n));
	}
	return 0;
}

图论

最短路

//这里的dist是longlong类型
//“通常用于求含负权边的单源最短路径,以及判负权环”
void spfa() {
    for(int i = 1; i <= n; i++)
        dist[i] = (1ll << 31) - 1;
    queue<int>q;
    dist[s] = 0; q.push(s); inq[s] = 1;
    while(!q.empty()) {
        int u = q.front(); q.pop();
        inq[u] = 0;
        for(int i = hd[u]; i; i = nxt[i]) {
            int v = to[i];
            if(dist[v] > dist[u] + val[i]) {
                dist[v] = dist[u] + val[i];
                if(!inq[v]) q.push(v);
            } 
        }
    }
    return;
}
//以下是判负环用的
//差分约束建虚点 注意边不要反 边权正负不要反 不要输错总点数(用于判断负环的入队次数)
bool spfa() {
	memset(dist, 0x3f, sizeof(dist));
	memset(inq, 0, sizeof(inq));
	memset(cnt, 0, sizeof(cnt));
	queue<int>q; q.push(s); inq[s] = 1; dist[s] = 0;  ++cnt[s];
	while(!q.empty()) {
		int u = q.front(); q.pop();
		inq[u] = 0;
		for(int i = hd[u]; i; i = nxt[i]) {
			int v = to[i];
			if(dist[v] > dist[u] + val[i]) {
				dist[v] = dist[u] + val[i];
				if(!inq[v]) {
					inq[v] = 1, q.push(v);
					if(++cnt[v] >= n) return 1;
				}
			}
		}
	}
	return 0;
}
//边权>=0
void dijkstra() {
	for(int i = 1; i <= n; i++)
		dist[i] = 2147483647;
	priority_queue<pair<int, int> >q;
	dist[s] = 0; q.push(mkp(dist[s], s));
	while(!q.empty()) {
		int u = q.top().se; q.pop();
		if(vis[u]) continue; vis[u] = 1;
		for(int i = hd[u]; i; i = nxt[i]) {
			int v = to[i];
			if(dist[v] > dist[u] + val[i]) {
				dist[v] = dist[u] + val[i];
				if(!vis[v]) q.push(mkp(-dist[v], v));
			}
		}
	}
}
//bellman-ford
for(int i = 1; i <= n; i++)
	for(int j = 1; j <= e; j++)
		if(dist[V[j]] > dist[U[j]] + valw[j])
			dist[V[j]] = dist[U[j]] + valw[j], pre[V[j]] = j;

最小生成树

bool prim() {
	for(int i = 1; i <= n; i++) dist[i] = inf; dist[1] = 0;
	priority_queue<pair<int, int> >q; q.push(mkp(0, 1));
	int tot = 0;
	while(!q.empty()) {
		int u = q.top().second; q.pop();
		if(vis[u]) continue; vis[u] = 1; tot++; ans += dist[u];
		for(int i = hd[u]; i; i = nxt[i]) {
			int v = to[i], w = val[i];
			if(!vis[v] && dist[v] > w) 
				dist[v] = w, q.push(mkp(-dist[v], v));
		}
	}
	return (tot == n);
}

kruskal 就不放了

无向图求割点和桥

void tarjan(int u, int ed) {
	dfn[u] = low[u] = ++tim;
	int son = 0;
	for(int i = hd[u]; i; i = nxt[i]) {
		if(i == (ed ^ 1)) continue;
		int v = to[i];
		if(!dfn[v]) {
			son++;
			tarjan(v, i);
			low[u] = min(low[u], low[v]);
			if(low[v] >= dfn[u] && u != rt) cut[u] = 1;
			if(low[v] > dfn[u]) isbridge[i] = 1;
		} else {
			low[u] = min(low[u], dfn[v]);
		}
	}
	if(u == rt) cut[u] = (son >= 2);
	return;
}
int main() {
	for(int i = 1; i <= n; i++)
		if(!dfn[i]) rt= i, tarjan(i, -1);
}
//缩点(强连通分量)
void tarjan(int u) {
	low[u] = dfn[u] = ++tim; st[++top] = u; ins[u] = 1;
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i];
		if(!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
		else if(ins[v]) low[u] = min(low[u], dfn[v]);
	}
	if(low[u] == dfn[u]) {
		++cnt;
		int v;
		do{
			v = st[top]; top--; ins[v] = 0;
			col[v] = cnt;
		}while(top > 0 && v != u);
	}
	return;
}

树相关

最近公共祖先 LCA

//O(nlogn)预处理 O(1)查询
void dfs(int u, int fa) {
	dep[u] = dep[fa] + 1; fat[u] = fa;
	dfn[u] = ++tim; st[dfn[u]][0] = u;
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fa) continue;
		dfs(v, u);
	}
	return;
}
int Min(int x, int y) {
	if(dep[x] <= dep[y]) return x;
	else return y;
}
int query(int a, int b) {
	if(dfn[a] > dfn[b]) swap(a, b);
	if(a == b) return a;
    int x = dfn[a] + 1, y = dfn[b];
	int t = Log[y - x + 1];
	return fat[Min(st[x][t], st[y - (1 << t) + 1][t])];
}
void init() {
	Log[0] = Log[1] = 0;
	for(int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;
	for(int j = 1; j <= Log[n]; j++)
		for(int i = 1; i + (1 << j) - 1 <= n; i++) {
			st[i][j] = Min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
		}
	return;
}
//预处理:dfs(s, 0); init();
//O(nlogn)预处理 O(logn) 查询
void dfs(int u, int fa){
	f[u][0] = fa; dep[u] = dep[fa] + 1;
	for(int i = 1; i <= 19; i++)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for(int i = hd[u], v; i; i = nxt[i])
		if((v = to[i]) != fa) dfs(v, u);
	return;
}
int lca(int x, int y){
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = 16; i >= 0; i--)
		if(dep[f[x][i]] >= dep[y])
			x = f[x][i];
	if(x == y) return x;
	for(int i = 16; i >= 0; i--)
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	return x = y = f[x][0];
}

prufer序列

//为方便你实现代码,尽管是无根树,我们在读入时仍将 n 设为其根。
const int N = 5e6 + 10;
int n, m, d[N], f[N], p[N];
void f_to_p() {
	for(int i = 1; i < n; i++) d[f[i]]++;
	for(int i = 1, j = 1; i <= n - 2; i++, j++) {
		while(d[j]) j++; p[i] = f[j];
		while(i <= n - 2 && !(--d[p[i]]) && p[i] < j)
			p[i + 1] = f[p[i]], i++;
	}
}
void p_to_f() {
	p[n - 1] = n; for(int i = 1; i <= n - 1; i++) d[p[i]]++;
	for(int i = 1, j = 1; i < n; i++, j++) {
		while(d[j]) j++; f[j] = p[i];
		while(i <= n - 2 && !(--d[p[i]]) && p[i] < j)
			f[p[i]] = p[i + 1], i++;
	}
}
int main() {
	scanf("%d%d", &n, &m);
	if(m == 1) {
		for(int i = 1; i < n; i++)
			scanf("%d", &f[i]);
		f_to_p();
		ll ans = 0;
		for(int i = 1; i <= n - 2; i++)
			ans ^= 1ll * i * p[i];
		printf("%lld\n", ans);
	} else {
		for(int i = 1; i <= n - 2; i++)
			scanf("%d", &p[i]);
		p_to_f();
		ll ans = 0;
		for(int i = 1; i < n; i++)
			ans ^= 1ll * i * f[i];
		printf("%lld\n", ans);
	}
	return 0;
}

树链剖分

const int N = 1e5 + 10;
int n, m, R, P, tim, sz[N], fat[N]; 
ll tr[N << 2], lz[N << 2];
int e, hd[N], nxt[N << 1], to[N << 1], son[N], top[N], dfn[N], dep[N];
int bgval[N], dyid[N];
void build(int rt, int l, int r) {
	tr[rt] = 0; lz[rt] = 0;
	if(l == r) {
		tr[rt] = bgval[dyid[l]];
		return;
	}
	int mid = (l + r) >> 1;
	build(ls(rt), l, mid);
	build(rs(rt), mid + 1, r);
	tr[rt] = (tr[ls(rt)] + tr[rs(rt)]) % P;
}
void update(int rt, int l, int r, int L, int R, int val) {
//	cout<<"update: "<<rt<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<" "<<val<<endl;
	if(L <= l && r <= R) {
		tr[rt] += (ll)val * (r - l + 1) % P; if(tr[rt] >= P) tr[rt] -= P;
		lz[rt] += val; if(lz[rt] >= P) lz[rt] -= P;
		return;
	}
	int mid = (l + r) >> 1;
	if(lz[rt]) {
		lz[ls(rt)] += lz[rt]; if(lz[ls(rt)] >= P) lz[ls(rt)] -= P;
		tr[ls(rt)] += (ll)(mid - l + 1) * lz[rt] % P; if(tr[ls(rt)] >= P) tr[ls(rt)] -= P;
		lz[rs(rt)] += lz[rt]; if(lz[rs(rt)] >= P) lz[rs(rt)] -= P;
		tr[rs(rt)] += (ll)(r - mid) * lz[rt] % P; if(tr[rs(rt)] >= P) tr[rs(rt)] -= P;
		lz[rt] = 0; 
	}
	if(L <= mid) {
		update(ls(rt), l, mid, L, R, val);
	}
	if(R > mid) {
		update(rs(rt), mid + 1, r, L, R, val);
	}
	tr[rt] = (tr[ls(rt)] + tr[rs(rt)]) % P;
	return;
}
int query(int rt, int l, int r, int L, int R) {
//	cout<<"query: "<<rt<<" "<<l<<" "<<r<<" "<<L<<" "<<R<<" "<<endl;
	if(L <= l && r <= R) {
		return tr[rt];
	}
	int mid = (l + r) >> 1;
	if(lz[rt]) {
		lz[ls(rt)] += lz[rt]; if(lz[ls(rt)] >= P) lz[ls(rt)] -= P;
		tr[ls(rt)] += (ll)(mid - l + 1) * lz[rt] % P; if(tr[ls(rt)] >= P) tr[ls(rt)] -= P;
		lz[rs(rt)] += lz[rt]; if(lz[rs(rt)] >= P) lz[rs(rt)] -= P;
		tr[rs(rt)] += (ll)(r - mid) * lz[rt] % P; if(tr[rs(rt)] >= P) tr[rs(rt)] -= P;
		lz[rt] = 0; 
	}
	int ret = 0;
	if(L <= mid) {
		ret += query(ls(rt), l, mid, L, R);
		if(ret >= P) ret -= P;
	}
	if(R > mid) {
		ret += query(rs(rt), mid + 1, r, L, R);
		if(ret >= P) ret -= P;
	}
	tr[rt] = (tr[ls(rt)] + tr[rs(rt)]) % P;
	return ret;
}
void dfs1(int u, int fa) {
	sz[u] = 1; fat[u] = fa; dep[u] = dep[fa] + 1;
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fa) continue;
		dfs1(v, u);
		sz[u] += sz[v];
		if(sz[v] > sz[son[u]]) son[u] = v; 
	}
	return;
}
void dfs2(int u, int topf) {
	top[u] = topf; dfn[u] = ++tim; dyid[tim] = u;
	if(son[u]) dfs2(son[u], topf);
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fat[u] || v == son[u]) continue;
		dfs2(v, v);
	}
	return;
}
void add_path(int x, int y, int z) {
	while(top[x] != top[y]) {
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		update(1, 1, n, dfn[top[x]], dfn[x], z);
		x = fat[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	update(1, 1, n, dfn[x], dfn[y], z);
	return;
}
int query_path(int x, int y) {
	int ret = 0;
	while(top[x] != top[y]) {
		if(dep[top[x]] < dep[top[y]]) swap(x, y);
		ret += query(1, 1, n, dfn[top[x]], dfn[x]); if(ret >= P) ret -= P;
		x = fat[top[x]];
	}
	if(dep[x] > dep[y]) swap(x, y);
	ret += query(1, 1, n, dfn[x], dfn[y]); if(ret >= P) ret -= P;
	return ret;
}
void add(int u, int v) {
	to[++e] = v; 
	nxt[e] = hd[u]; hd[u] = e;
}
int main() {
//    freopen("ex.in", "r", stdin);
//    freopen("ex.out", "w", stdout);
	rd(n); rd(m); rd(R); rd(P);
	for(int i = 1; i <= n; i++)
		rd(bgval[i]), bgval[i] = bgval[i] % P;
	for(int i = 1, x, y; i < n; i++)
		scanf("%d%d", &x, &y), add(x, y), add(y, x);
	dfs1(R, 0); dfs2(R, R);
	build(1, 1, n);
//	puts("devin");
   for(int i = 1, op, x, y, z; i <= m; i++) {
		rd(op);
		if(op == 1) {
			rd(x); rd(y); rd(z);
			z = z % P;
			add_path(x, y, z);
		} else if(op == 2) {
			rd(x); rd(y);
			printf("%d\n", query_path(x, y));
		} else if(op == 3) {
		//	puts("zdsfhlkdhgjdfl");
			rd(x); rd(z);
			z = z % P;
			update(1, 1, n, dfn[x], dfn[x] + sz[x] - 1, z);
		} else {
			rd(x);
			printf("%d\n", query(1, 1, n, dfn[x], dfn[x] + sz[x] - 1));
		}
   }
    return 0;
}

长链剖分 树上k级祖先

#define ui unsigned int
ui s; inline ui get(ui x) { x ^= x << 13; x ^= x >> 17; x ^= x << 5; return s = x; }
const int N = 5e5 + 10;
int n, cnt[N], sz[N], dep[N], son[N], d[N], f[N][25], Log[N], top[N];
int e, hd[N], to[N << 1], nxt[N << 1];
vector<int>up[N], down[N];
void add(int u, int v) { to[++e] = v; nxt[e] = hd[u]; hd[u] = e; } 
void dfs1(int u, int fa) {
	sz[u] = 1; d[u] = dep[u] = dep[fa] + 1;
	f[u][0] = fa;
	for(int i = 1; i <= Log[n]; i++)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fa) continue;
		dfs1(v, u);
		if(d[v] > d[u]) son[u] = v, d[u] = d[v];
	} 
	return;
}
void dfs2(int u, int topf) {
	top[u] = topf;
	if(u == topf) {
		for(int i = 0, v = u; i <= d[u] - dep[u]; i++)
			up[u].push_back(v), v = f[v][0];
		for(int i = 0, v = u; i <= d[u] - dep[u]; i++)
			down[u].push_back(v), v = son[v];
	}
	if(son[u]) dfs2(son[u], topf);
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == f[u][0] || v == son[u]) continue;
		dfs2(v, v);
	} 
}
int query(int x, int k) {
	if(!k) return x;
	x = f[x][Log[k]]; k -= (1 << Log[k]);
	k -= dep[x] - dep[top[x]]; x = top[x];
	return (k >= 0) ? up[x][k] : down[x][-k];
}
int main(){
	int q; scanf("%d%d%u", &n, &q, &s);
	Log[1] = 0; for(int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;
	int rt = 0;
	for(int i = 1, x; i <= n; i++) {
		scanf("%d", &x);
		if(x == 0) rt = i;
		else add(x, i), add(i, x);
	}
	dfs1(rt, 0); dfs2(rt, rt);
	int ans = 0; ll res = 0;
	for(int i = 1; i <= q; i++) {
		int x = (get(s) ^ ans) % n + 1;
		int k = (get(s) ^ ans) % dep[x];
		res ^= 1ll * i * (ans = query(x, k));
	}
	printf("%lld\n", res);
	return 0;
}

点分治

const int N = 1e4 + 10, inf = 0x3f3f3f3f, M = 1e7 + 10;
int n, m, siz, rt, cnt;
int sz[N], mxsz[N], ask[N];
int td[N];
bool vis[N], okd[M], ans[110];
int e, hd[N], nxt[N << 1], to[N << 1], val[N << 1];
void add(int u, int v, int w) {
	to[++e] = v; val[e] = w;
	nxt[e] = hd[u]; hd[u] = e;
}
void getrt(int u, int fa) {
	sz[u] = 1; mxsz[u] = 0;
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fa || vis[v]) continue;
		getrt(v, u);
		sz[u] += sz[v]; mxsz[u] = max(mxsz[u], sz[v]);
	}
	mxsz[u] = max(mxsz[u], siz - sz[u]);
	if(mxsz[u] < mxsz[rt]) rt = u;
	return;
}
void getdis(int u, int fa, int dis) {
//	cout<<u<<"*"<<fa<<" "<<dis<<endl;
	if(dis > 1e7) return;
	td[++cnt] = dis;
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(v == fa || vis[v]) continue;
		getdis(v, u, dis + val[i]);
	}
	return;
}
void calc(int u) {
//	cout<<"calc: "<<u<<endl;
	cnt = 0;
	okd[0] = 1;
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(vis[v]) continue;
		int pc = cnt;
		getdis(v, u, val[i]);
		for(int j = pc + 1; j <= cnt; j++) {
		//	cout<<td[j]<<endl;
			for(int k = 1; k <= m; k++)
				if(ask[k] >= td[j] && okd[ask[k] - td[j]])
					ans[k] = 1;
		}
		for(int j = pc + 1; j <= cnt; j++)
			okd[td[j]] = 1;
	}
	okd[0] = 0;
	for(int i = 1; i <= cnt; i++)
		okd[td[i]] = 0;
	return;
}
void solve(int u) {
	vis[u] = 1; calc(u);
	for(int i = hd[u]; i; i = nxt[i]) {
		int v = to[i]; if(vis[v]) continue;
		rt = 0; siz = sz[v]; getrt(v, 0); solve(rt);
	}
	return;
}
void init() {
	mxsz[0] = inf;
	return;
}
int main(){
	init();
	scanf("%d%d", &n, &m);
	for(int i = 1, u, v, w; i < n; i++) {
		scanf("%d%d%d", &u, &v, &w);
		add(u, v, w); add(v, u, w);
	}
	for(int i = 1; i <= m; i++)
		scanf("%d", &ask[i]);
	rt = 0; siz = n; getrt(1, 0);
	solve(rt);
	for(int i = 1; i <= m; i++)
		puts((!ans[i]) ? "NAY" : "AYE");
	return 0;
}

点分树

#include<bits/stdc++.h>
using namespace std;
#define mkp make_pair
#define pb push_back
typedef long long ll;
const int N = 1e5 + 10, inf = 0x3f3f3f3f;
int n, m, val[N], fat[N], dist[N];
int lim = 20, dept[N], f[N][25];
int rt, sum, vis[N], sz[N], mxsz[N];
vector<ll>tr[N][2];
//0: 自己的贡献 1:对fa[u]的贡献 
int e, to[N << 1], nxt[N << 1], hd[N];
void add(int a, int b){
	to[++e] = b; nxt[e] = hd[a]; hd[a] = e;
}
void clear(){
	for(int i = 1; i <= n; i++){
		vis[i] = dept[i] = fat[i] = 0;
		vector<ll>().swap(tr[i][0]);
		vector<ll>().swap(tr[i][1]);
	}
	e = 0;
	memset(to, 0, sizeof(to));
	memset(nxt, 0, sizeof(nxt));
	memset(hd, 0, sizeof(hd));
}
/* ------------------------------------------------ */ 
void dfs(int u, int fa){
	dept[u] = dept[fa] + 1;
	f[u][0] = fa;
	for(int i = 1; i <= lim; i++)
		f[u][i] = f[f[u][i - 1]][i - 1];
	for(int i = hd[u]; i; i = nxt[i]){
		int v = to[i]; if(v == fa) continue;
		dfs(v, u); 
	}
	return;
}
int lca(int x, int y){
	if(dept[x] < dept[y]) swap(x, y);
	for(int i = lim; i >= 0; i--)
		if(dept[f[x][i]] >= dept[y])
			x = f[x][i];
	if(x == y) return x;
	for(int i = lim; i >= 0; i--)
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	return f[x][0];
} 
int calc_dis(int x, int y){
	int t = lca(x, y);
	return dept[x] + dept[y] - 2 * dept[t];
} 
/* ------------------------------------------------ */ 
int cnt = 0;
void getrt(int u, int fa){
	sz[u] = 1; mxsz[u] = 0;
	for(int i = hd[u]; i; i = nxt[i]){
		int v = to[i]; if(v == fa || vis[v]) continue; 
		getrt(v, u); sz[u] += sz[v];
		mxsz[u] = max(mxsz[u], sz[v]);
	}
	mxsz[u] = max(mxsz[u], sum - sz[u]);
	if(mxsz[u] <= mxsz[rt]) rt = u;
	return;
}
/* ------------------------------------------------ */ 
int lowbit(int x){
	return x & -x;
}
void insert(int id, int op, int x, int val){
	if(x < 0) return; 
	x++;
	for(; x < tr[id][op].size(); x += lowbit(x))
		tr[id][op][x] += val;
	return; 
}
ll query(int id, int op, int x){
	if(x < 0) return 0;
	x++; if(x >= tr[id][op].size()) x = tr[id][op].size() - 1;
	ll ret = 0;
	for(; x; x -= lowbit(x))
		ret += tr[id][op][x];
	return ret;
}
/* ------------------------------------------------ */ 
void calc(int rot, int op, int u, int fa){
	insert(rot, op, dist[u], val[u]);
	for(int i = hd[u]; i; i = nxt[i]){
		int v = to[i]; if(v == fa || vis[v]) continue;
		dist[v] = dist[u] + 1;	
		calc(rot, op, v, u);
	}
}
void getpre(int u){
	vis[u] = 1; dist[u] = 0; calc(u, 0, u, 0);
	for(int i = hd[u]; i; i = nxt[i]){
		int v = to[i]; if(vis[v]) continue;
		rt = 0; sum = sz[v]; getrt(v, 0);
		tr[rt][0].resize(sz[v] + 2);
		tr[rt][1].resize(sz[v] + 2);
		dist[v] = 1; calc(rt, 1, v, u); fat[rt] = u;
		getpre(rt);
	}
	return; 
}

void init(){
	mxsz[0] = inf;
	rt = 0; sum = n; getrt(1, 0);
	tr[rt][0].resize(n + 2);
	tr[rt][1].resize(n + 2);
	getpre(rt);
} 
/* ------------------------------------------------ */ 
void update(int x, int y){
	insert(x, 0, 0, y - val[x]);
	for(int i = x; fat[i]; i = fat[i]){
		int dis = calc_dis(x, fat[i]);
		insert(fat[i], 0, dis, y - val[x]);
		insert(i, 1, dis, y - val[x]);
	}
	val[x] = y;
	return;
}
ll solve(int x, int y){
	ll ret = query(x, 0, y);
	for(int i = x; fat[i]; i = fat[i]){
		int dis = calc_dis(x, fat[i]);
		ret += query(fat[i], 0, y - dis);
		ret -= query(i, 1, y - dis);
	}
	return ret;
} 
/* ------------------------------------------------ */ 
int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%d", &val[i]);
	for(int i = 1, u, v; i < n; i++)
		scanf("%d%d", &u, &v), add(u, v), add(v, u);
	dfs(1, 0); init();
	ll lst = 0; 
	for(int i = 1, x, y; i <= m; i++){
		int op; scanf("%d%d%d", &op, &x, &y);
		x ^= lst; y ^= lst;
		if(!op) printf("%lld\n", lst = solve(x, y));
		else update(x, y);
	} 
	return 0;
}

字符串相关

哈希

void pre(){
    p[0] = 1; f[0] = 0;
    for(int i = 1; i <= n; i++){
        f[i] = (1ll * f[i-1] * 29 + s[i] - 'a' + 1) % mod;
        p[i] = 1ll * p[i-1] * 29 % mod;
    }
}
int calc(int l, int r){
    return ((f[r] - 1ll * f[l-1] * p[r - l + 1] % mod) %mod + mod) % mod;
}

KMP

void init() {
	int j = 0;
	for(int i = 2; i <= n2; i++) {
		while(j && s2[j + 1] != s2[i]) j = p[j];
		if(s2[j + 1] == s2[i]) j++;
		p[i] = j;
	}
	return;
}
void kmp() {
	int j = 0;
	for(int i = 1; i <= n1; i++) {
		while(j && s2[j + 1] != s1[i]) j = p[j];
		if(s2[j + 1] == s1[i]) j++;
		if(j == n2) {
			printf("%d\n", i - n2 + 1);
			j = p[j];
		}
	}
	return;
}

manacher

const int N = 1.1e7 + 10; 
char s[N], s2[N << 1];
int p[N << 1];
int manacher() {
	int n = strlen(s + 1), m = 0;
	for(int i = 1; i <= n; i++)
		s2[++m] = '#', s2[++m] = s[i]; 
	s2[++m] = '#';
	int mxlen = 0, id = 1, mx = 1; 
	p[1] = 1;
	for(int i = 2; i <= m; i++) {
		p[i] = (i < mx) ? min(p[2 * id - i], mx - i) : 1;
		while(1 <= i - p[i] && i + p[i] <= m && s2[i - p[i]] == s2[i + p[i]]) p[i]++;
			
		if(mx < i + p[i]) mx = i + p[i], id = i;
		mxlen = max(mxlen, p[i] - 1);
	}
	return mxlen;
}
int main(){
	scanf("%s", s + 1);
	printf("%d\n", manacher());
	return 0;
}

AC自动机

const int M = 2e6 + 10;
int n, fail[M], tot[M], cnt; 
int tr[M][30], dy[M];
char s[M]; 
int e, to[M << 1], nxt[M << 1], hd[M], in[M];
void ins(char *s, int i) {
	int len = strlen(s + 1);
	int p = 0;
	for(int i = 1; i <= len; i++) {
		int c = s[i] - 'a';
		if(!tr[p][c]) tr[p][c] = ++cnt;
		p = tr[p][c];
	}
	dy[i] = p;
}
void getfail() {
	queue<int>q;
	for(int i = 0; i < 26; i++)
		if(tr[0][i]) q.push(tr[0][i]);
	while(!q.empty()) {
		int p = q.front(); q.pop();
		for(int i = 0; i < 26; i++)
			if(tr[p][i]) fail[tr[p][i]] = tr[fail[p]][i], q.push(tr[p][i]);
			else tr[p][i] = tr[fail[p]][i];
	}
	return;
}
void query(char *s) {
	int len = strlen(s + 1);
	int p = 0;
	for(int i = 1; i <= len; i++) {
		int c = s[i] - 'a';
		p = tr[p][c];
		tot[p]++;
	}
	for(int i = 1; i <= cnt; i++)
		in[fail[i]]++;
	queue<int>q; 
	for(int i = 0; i <= cnt; i++)
		if(!in[i]) q.push(i);
	while(!q.empty()) {
		int u = q.front(); q.pop();
		in[fail[u]]--; tot[fail[u]] += tot[u];
		if(in[fail[u]] == 0) q.push(fail[u]);
	}
	return;
}
int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		scanf("%s", s + 1), ins(s, i);
	getfail();
	scanf("%s", s + 1);
	query(s);
	for(int i = 1; i <= n; i++)
		printf("%d\n", tot[dy[i]]);
	return 0;
}
/*
给你一个文本串 S 和 n个模式串 T 1∼n ,请你分别求出每个模式串 Ti在 S中出现的次数。
*/

SAM

const int maxn=1e6+10;
char s[maxn];
int n,f[maxn<<1],ans[maxn];
int e,hd[maxn<<1],to[maxn<<2],nxt[maxn<<2],in[maxn<<1];
void add(int a,int b){ to[++e]=b; nxt[e]=hd[a]; hd[a]=e; in[b]++; }
struct SAMSAM{
    int sz,lst;
    int maxlen[maxn<<1],trans[maxn<<1][26],link[maxn<<1];
    bool vis[maxn<<1];
    SAMSAM(){ sz=lst=1; }
    void extend(int c){
        int cur=(++sz),p;
        vis[cur]=1;
        maxlen[cur]=maxlen[lst]+1;
        for(p=lst;p&&!trans[p][c];p=link[p]) trans[p][c]=cur;
        if(!p) link[cur]=1;
        else {
            int q=trans[p][c];
            if(maxlen[q]==maxlen[p]+1) link[cur]=q;
            else {
                int cln=++sz;
                maxlen[cln]=maxlen[p]+1;
                for(int i=0;i<26;i++) trans[cln][i]=trans[q][i];
                link[cln]=link[q];

                for(;p&&trans[p][c]==q;p=link[p]) trans[p][c]=cln;

                link[cur]=link[q]=cln;
            }
        }
        lst=cur;
    }
    ll topo(){
        ll res=0;
        queue<int>q;
        for(int i=1;i<=sz;i++){
            if(!in[i]) q.push(i);
            if(vis[i]) f[i]=1;
        }
        while(!q.empty()){
            int u=q.front(); q.pop();
            if(f[u]>1) res=max(res,1ll*maxlen[u]*f[u]);
            for(int i=hd[u];i;i=nxt[i]){
                int v=to[i]; in[v]--;
                f[v]+=f[u];
                if(in[v]==0) q.push(v);
            }
        }
        return res;
    }
    void query(){
        for(int i=1;i<=sz;i++)
            if(link[i]) add(i,link[i]);
        printf("%lld\n",topo());
    }
}SAM;
int main(){
    scanf("%s",s+1); n=strlen(s+1);
    for(int i=1;i<=n;i++)
        SAM.extend(s[i]-'a');
    SAM.query();
    return 0;
}

广义SAM

//在线构造标准写法
const int N=4e5+10,M=1e6+10;
int n;
struct SAMSAM{
    int sz;
    int trans[M<<1][27],link[M<<1],maxlen[M<<1];
    SAMSAM(){ sz=1; }
    int extend(int c,int lst){
        int p,cln;
        if(trans[lst][c]){
            p=lst; int q=trans[p][c];
            if(maxlen[lst]+1==maxlen[q]) return q;//特判1
            else {
                cln=(++sz);
                maxlen[cln]=maxlen[p]+1;
                for(int i=0;i<26;i++) trans[cln][i]=trans[q][i];
                for(;p&&trans[p][c]==q;p=link[p]) trans[p][c]=cln;
                link[cln]=link[q]; link[q]=cln;
                return cln;//特判2
            }
        }
        int cur=(++sz);
        maxlen[cur]=maxlen[lst]+1;
        for(p=lst;p&&!trans[p][c];p=link[p]) trans[p][c]=cur;
        if(!p) link[cur]=1;
        else {
            int q=trans[p][c];
            if(maxlen[q]==maxlen[p]+1) link[cur]=q;
            else {
                cln=(++sz);
                maxlen[cln]=maxlen[p]+1;
                for(int i=0;i<26;i++) trans[cln][i]=trans[q][i];
                for(;p&&trans[p][c]==q;p=link[p]) trans[p][c]=cln;
                link[cln]=link[q]; link[cur]=link[q]=cln;
            }
        }
        return cur;
    }
    void ins(char* s){
        int nw=1,len=strlen(s+1);
        for(int i=1;i<=len;i++)
            nw=extend(s[i]-'a',nw);
        return;
    }
    void query(){
        ll res=0;
        for(int i=2;i<=sz;i++)
            res+=maxlen[i]-maxlen[link[i]];
        printf("%lld\n",res);
        return;
    }
}SAM;
int main(){
    char s[M];
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%s",s+1),SAM.ins(s);
    SAM.query();
    return 0;
}

后缀排序

const int N = 1e6 + 10;
int n, hs[N], pw[N], id[N]; char s[N];
ull query(int l, int r) {
	return hs[r] - hs[l - 1] * pw[r - l + 1];
}
int lcp(int x, int y) {
	int l = 0, r = min(n - x + 1, n - y + 1), bst = 0;
	while(l <= r) {
		int mid = (l + r) / 2;
		if(query(x, x + mid - 1) == query(y, y + mid - 1))
			l = mid + 1, bst = mid;
		else r = mid - 1;
	}
	return bst;
}
bool cmp(int x, int y) {
	int bst = lcp(x, y);
	if(bst == min(n - x + 1, n - y + 1)) return x > y;
	return s[x + bst] < s[y + bst];
}
int main() {
	scanf("%s", s + 1);
	n = strlen(s + 1);
	pw[0] = 1;
	for(int i = 1; i <= n; i++) {
		pw[i] = pw[i - 1] * 131;
		hs[i] = hs[i - 1] * 131 + s[i] - 'a' + 1;
		id[i] = i;
	}
	stable_sort(id + 1, id + n + 1, cmp);
	for(int i = 1; i <= n; i++)
		printf("%d ", id[i]);
    return 0;
}

计算几何

二维凸包

const int N = 1e5 + 10;
int n;
struct node {
	double x, y;
	node(){}
	node(double a, double b) {
		x = a; y = b;
	}
	bool operator < (const node a) const {
		if(x == a.x) return y < a.y;
		return x < a.x;
	}
	friend node operator - (node a, node b) {
		return node(a.x - b.x, a.y - b.y);
	}
}p[N]; 
double Cross(node a, node b) {
	return a.x * b.y - a.y * b.x;
}
int top = 0, st[N];
int main() {
	rd(n);
	for(int i = 1; i <= n; i++) {
		scanf("%lf%lf", &p[i].x, &p[i].y);
	}
	sort(p + 1, p + n + 1);
	for(int i = 1; i <= n; i++) {
		while(top >= 2 && Cross(p[st[top]] - p[st[top - 1]], p[i] - p[st[top]]) <= 0)
			top--;
		st[++top] = i;
	}
	int ktop = top;
	for(int i = n - 1; i >= 1; i--) {
		while(top >= ktop + 1 && Cross(p[st[top]] - p[st[top - 1]], p[i] - p[st[top]]) <= 0)
			top--;
		st[++top] = i;
	}
	if(top > 1) top--;
	st[top + 1] = st[1];
	double ans = 0;
	for(int i = 1; i <= top; i++)
		ans += sqrt((p[st[i + 1]].x - p[st[i]].x) * (p[st[i + 1]].x - p[st[i]].x) + (p[st[i + 1]].y - p[st[i]].y) * (p[st[i + 1]].y - p[st[i]].y));
	printf("%.2lf\n", ans);
    return 0;
}

旋转卡壳(内部好像含有很多计算几何相关?)

double eps = 1e-8, inf = 1e15, Pi = acos(-1.0);
const int N = 200010;
int dcmp(double x) {
    if(fabs(x) < eps) return 0;
    return (x < 0) ? -1 : 1;
}
struct Point {
    double x, y;
    Point() { x = y = 0; }
    Point(double a, double b) { x = a; y = b; }
    friend Point operator + (Point a, Point b) { return Point(a.x + b.x, a.y + b.y); }
    friend Point operator - (Point a, Point b) { return Point(a.x - b.x, a.y - b.y); }
    friend Point operator * (Point a, double b) { return Point(a.x * b, a.y * b); }
    friend Point operator / (Point a, double b) { return Point(a.x / b, a.y / b); }
    friend bool operator == (Point a, Point b) { return (dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0); }
    bool operator < (const Point a) const {
        return (x != a.x) ? (x < a.x) : (y < a.y);
    }
    Point turn(Point p0, double ang) {
        Point p = Point(x, y);
        Point tmp = (p - p0);
        tmp.x = tmp.x * cos(ang) - tmp.y * sin(ang);
        tmp.y = tmp.y * sin(ang) + tmp.y * cos(ang);
        return p0 + tmp;
    }
};
typedef Point Vector;
struct Line {
    //l=(1-t)A+tB=A+t(B-A)=x+ty
    Point p; Vector v;
    Line() { p.x = p.y = v.x = v.y = 0; }
    Line(Point a, Point b) { p = a; v = b - a; }
};
double Dot(Point a, Point b) { return a.x * b.x + a.y * b.y; } 
double Cross(Point a, Point b) { return a.x * b.y - a.y * b.x; } 
double Len(Point a) { return sqrt(a.x * a.x + a.y * a.y); }

double LineProjection(Point p, Point p1, Point p2) { return Dot(p - p1, p2 - p1) / Len(p2 - p1); }
Point ProjectionPoint(Point p, Point p1, Point p2) { return p1 + (p2 - p1) * LineProjection(p, p1, p2) / Len(p2 - p1); }
Point ReflectionPoint(Point p, Point p1, Point p2) { return ProjectionPoint(p, p1, p2) * 2 - p; }
void Clockwise(Point p, Point p1, Point p2) {
    double cr = Cross(p1 - p, p2 - p);
    if(cr) {
        if(cr > 0) puts("COUNTER_CLOCKWISE");
        else puts("CLOCKWISE");
    } else {
        double lp = LineProjection(p, p1, p2);
        if(lp < 0) puts("ONLINE_BACK");
        else if(lp - Len(p2 - p1) > 0) puts("ONLINE_FRONT");
        else puts("ON_SEGMENT");
    }
}
bool isOnSegment(Point p, Point p1, Point p2) {
    //若允许在点与端点重合
    if(p == p1 || p == p2) return 1;
    return (dcmp(Cross(p1 - p, p2 - p)) == 0 && dcmp(Dot(p1 - p, p2 - p)) < 0);
    //若不允许点与端点重合
    //return (Len(P - A) + Len(B - P) - Len(B - A) == 0);
}
void LinePO(Line l1, Line l2) {
    if(Cross(l1.v, l2.v) == 0) puts("2");
    else if(Dot(l1.v, l2.v) == 0) puts("1");
    else puts("0");
}
int SegmentProperIntersection(Line l1, Line l2) {
    Point a1 = l1.p, a2 = l1.p + l1.v, b1 = l2.p, b2 = l2.p + l2.v;
    //若不允许在端点处相交,删去下一行
    if(isOnSegment(a1, b1, b2) || isOnSegment(a2, b1, b2) || isOnSegment(b1, a1, a2) || isOnSegment(b2, a1, a2)) return 1;
    double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);
    double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);
    //cout<<(dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0)<<endl;
    return (dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0);
}
Point LineIntersection(Line a, Line b) {
    Point p = a.p, q = b.p;
    Vector v = a.v, w = b.v, u = p - q;
    double t = Cross(w, u) / Cross(v, w);
    return p + v * t;
}
double DistanceToLine(Point a, Line b) {
    Point b1 = b.p, b2 = b.p + b.v;
    Point t = ProjectionPoint(a, b1, b2);
    return Len(a - t);
}
double DistanceToSeg(Point a, Line b) {
    Point b1 = b.p, b2 = b.p + b.v;
    Point t = ProjectionPoint(a, b1, b2);
    if(!isOnSegment(t, b1, b2)) return inf;
    return Len(a - t);
}
double SegmentDistance(Line a, Line b) {
    if(SegmentProperIntersection(a, b)) return 0;
    Point a1 = a.p, a2 = a.p + a.v, b1 = b.p, b2 = b.p + b.v;
    double x = min(min(DistanceToSeg(a1, b), DistanceToSeg(a2, b)), min(DistanceToSeg(b2, a), DistanceToSeg(b1, a)));
    double y = min(min(Len(a1 - b1), Len(a1 - b2)), min(Len(a2 - b1), Len(a2 - b2)));
    return min(x, y);
}
double PolygonArea(int n, Point *p) {
    double ret = 0;
    for(int i = 2; i <= n; i++)
        ret += Cross(p[i] - p[1], p[(i + 1 > n) ? 1 : (i + 1)] - p[1]);
    return fabs(ret) / 2;
}
int isConvex(int n, Point *p) {
    p[n + 1] = p[1]; p[n + 2] = p[2];
    for(int i = 1; i <= n; i++)
        if(Cross(p[i] - p[i + 1], p[i + 2] - p[i + 1]) > 0) return 0;
    return 1;
}

int PointinPolygon(Point p0, int n, Point *p) {
    //cout<<"calc:"<<endl;
    p[n + 1] = p[1];
    for(int i = 1; i <= n; i++)
        if(isOnSegment(p0, p[i], p[i + 1])) return 1;
    int cnt = 0;
    for(int i = 1; i <= n; i++) {
        Point a = p[i], b = p[i + 1];
        if(a.y > b.y) swap(a, b);
        if(dcmp(Cross(a - p0, b - p0)) < 0 && dcmp(a.y - p0.y) < 0 && dcmp(p0.y - b.y) <= 0)
            cnt++;
    }
    if(cnt & 1) return 2;
    return 0;
}
void ConvexHull(int n, Point *p, int &m, Point *q) {
    sort(p + 1, p + n + 1);
    m = 0;
    for(int i = 1; i <= n; i++) {
        while(m > 1 && Cross(p[i] - q[m], q[m - 1] - q[m]) >= 0) m--;
        q[++m] = p[i];
    }
    int k = m;
    for(int i = n - 1; i >= 1; i--) {
        while(m > k && Cross(p[i] - q[m], q[m - 1] - q[m]) >= 0) m--;
        q[++m] = p[i];
    }
    if(p[0] == p[m] && n > 1) m--;
    return;
}
double squaredist(Point a) {
   // cout<<a.x<<" "<<a.y<<endl;
    return a.x * a.x + a.y * a.y;
}
double MaxDistConvex(int n, Point *p) {
    if(n == 1) return 0;
    if(n == 2) return squaredist(p[2] - p[1]); 
    double ans = 0;
    p[n + 1] = p[1];
    int j = 2, bg = 2;
    for(int i = 1; i <= n; i++) {
        //对于边(p[i], p[i+1])
        while(dcmp(fabs(Cross(p[j] - p[i], p[i + 1] - p[i])) - fabs(Cross(p[j % n + 1] - p[i], p[i + 1] - p[i]))) <= 0) {
            if(j == bg) break;
            ans = max(ans, max(squaredist(p[j] - p[i]), squaredist(p[j] - p[i + 1])));
            j = j % n + 1;
        }
        if(i == 1) bg = i;
        ans = max(ans, max(squaredist(p[j] - p[i]), squaredist(p[j] - p[i + 1])));
        ans = max(ans, squaredist(p[i] - p[i + 1]));
    }
    return ans;
}   
int main(){
    //freopen("ex.in", "r", stdin);
    //freopen("ex.out", "w", stdout);
    static Point p[N];
    int n; scanf("%d", &n);
    for(int i = 1; i <= n; i++) 
        scanf("%lf%lf", &p[i].x, &p[i].y);
    int m; static Point q[N << 1];
    ConvexHull(n, p, m, q);
    ll tmp =  MaxDistConvex(m, q);
    printf("%lld\n", tmp);
    return 0;
}
/*
转过的角度应当>=Pi
*/

多项式

高精度乘法

const int N=4e6+10;
double pi=acos(-1.0);
int n,m,ans[N],id[N];
struct cplx{
    double x,y;
    cplx(double xx=0,double yy=0){ x=xx; y=yy; }
}f[N],g[N];
cplx operator + (cplx a,cplx b){ return cplx(a.x+b.x,a.y+b.y); }
cplx operator - (cplx a,cplx b){ return cplx(a.x-b.x,a.y-b.y); }
cplx operator * (cplx a,cplx b){ return cplx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); }
void FFT(int lim,cplx *a,int tp){
    for(int i=0;i<lim;i++) if(i<id[i]) swap(a[i],a[id[i]]);
    for(int mid=1;mid<lim;mid<<=1){
        cplx wn(cos(pi/mid),tp*sin(pi/mid));
        for(int j=0,len=mid<<1;j<lim;j+=len){
            cplx w(1,0);
            for(int k=0;k<mid;k++,w=wn*w){
                cplx x=a[j+k],y=w*a[j+k+mid];
                a[j+k]=x+y; a[j+k+mid]=x-y;
            }
        }
    }
    return;
}
int main(){
    char s[N];
    scanf("%s",s); n=strlen(s)-1;
    for(int i=0;i<=n;i++) f[i].x=s[n-i]-'0';
    scanf("%s",s); m=strlen(s)-1;
    for(int i=0;i<=m;i++) g[i].x=s[m-i]-'0';
    int lim=1,len=0; while(lim<=n+m) lim<<=1,len++;
    for(int i=0;i<lim;i++) id[i]=(id[i>>1]>>1)|((i&1)<<(len-1));
    
    FFT(lim,f,1); FFT(lim,g,1);
    for(int i=0;i<lim;i++) f[i]=f[i]*g[i];
    FFT(lim,f,-1);

    int sz=m+n;
    for(int i=0;i<=sz;i++){
        ans[i]+=(int)(f[i].x/lim+0.5);
        if(ans[i]>=10){
            int tmp=ans[i]/10;
            ans[i+1]+=tmp;
            ans[i]-=10*tmp;
            sz+=(i==sz);
        }
    }
    for(int j=sz;j>=0;j--) printf("%d",ans[j]);
    puts("");
    return 0;
}

FFT

const int N = 4e6 + 10, mod = 998244353;
int power(int x, int y) {
	int ret = 1;
	while(y) {
		if(y & 1) ret = 1ll * ret * x % mod;
		y >>= 1; x = 1ll * x * x % mod;
	}
	return ret;
}
namespace poly {
	int lim, le, id[N], ivlim, pre[N];
	void init(int n, int m) {
		lim = 1; while(lim <= n + m + 2) lim <<= 1, le++;
		ivlim = power(lim, mod - 2);		
		
		id[0] = 0; for(int i = 1; i < lim; i++) id[i] = id[i >> 1] >> 1 | ((i & 1) << (le - 1));
		pre[0] = 1;
		for(int mid = 1; mid < lim; mid <<= 1) {
			int wn = power(3, (mod - 1) / (mid << 1));
			for(int j = 0, w = 1; j < mid; j++, w = 1ll * w * wn % mod)
				pre[mid + j] = w;
		}
	}
	void NTT(int *a, int tp) {
		for(int i = 0; i < lim; i++)
			if(id[i] > i) swap(a[i], a[id[i]]);
		for(int mid = 1; mid < lim; mid <<= 1) {
			for(int i = 0, len = (mid << 1); i < lim; i += len) {
				for(int j = 0; j < mid; j++) {
					int x = a[i + j], y = 1ll * pre[mid + j] * a[i + j + mid] % mod;
					a[i + j] = (x + y) % mod;
					a[i + j + mid] = (x + mod - y) % mod;
				}
			}
		}
		if(tp) {
			for(int i = 0; i < lim; i++)
				a[i] = 1ll * a[i] * ivlim % mod;
			reverse(a + 1, a + lim);
		}
		return;
	}
	void getmul(int n, int m,int *f, int *g, int *h) {
		NTT(f, 0); NTT(g, 0);
		for(int i = 0; i < lim; i++) h[i] = 1ll * f[i] * g[i] % mod;
		NTT(h, 1);
		return;
	}
}
int main() {
	int n, m;
	static int f[N], g[N], h[N];
	scanf("%d%d", &n, &m);
	for(int i = 0; i <= n; i++) scanf("%d", &f[i]);
	for(int i = 0; i <= m; i++) scanf("%d", &g[i]);
	poly::init(n, m);
	poly::getmul(n, m, f, g, h);
	for(int i = 0; i <= n + m; i++)
		printf("%d ", h[i]);
	puts("");
	return 0;
}

FMT & FWT

const int N = (1 << 17) + 5, mod = 998244353;
int n, iv2;
int power(int x, int y) {
	int ret = 1;
	while(y) {
		if(y & 1) ret = 1ll * ret * x % mod;
		y >>= 1; x = 1ll * x * x % mod;
	}
	return ret;
} 
void FWT_or(int *a, int op) {
	for(int mid = 1; mid < n; mid <<= 1) 
		for(int i = 0, len = (mid << 1); i < n; i += len) 
			for(int j = 0; j < mid; j++) 
				a[mid + i + j] = (!op) ? (a[mid + i + j] + a[i + j]) % mod : (a[mid + i + j] + mod - a[i + j]) % mod;
}
void solve_or(int *a, int *b, int *c) {
	FWT_or(a, 0); FWT_or(b, 0);
	for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % mod;
	FWT_or(c, 1);
	for(int i = 0; i < n; i++)
		printf("%d ", c[i]);
	puts("");
}
void FWT_and(int *a, int op) {
	for(int mid = 1; mid < n; mid <<= 1) 
		for(int i = 0, len = (mid << 1); i < n; i += len) 
			for(int j = 0; j < mid; j++) 
				a[i + j] = (!op) ? (a[i + j] + a[mid + i + j]) % mod : (a[i + j] + mod - a[mid + i + j]) % mod;
}
void solve_and(int *a, int *b, int *c) {
	FWT_and(a, 0); FWT_and(b, 0);
	for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % mod;
	FWT_and(c, 1);
	for(int i = 0; i < n; i++)
		printf("%d ", c[i]);
	puts("");
}
void FWT_xor(int *a, int op) {
	for(int mid = 1; mid < n; mid <<= 1) 
		for(int i = 0, len = (mid << 1); i < n; i += len) 
			for(int j = 0; j < mid; j++) {
				int x = a[i + j], y = a[mid + i + j];
				a[i + j] = (x + y) % mod; a[mid + i + j] = (x + mod - y) % mod;
				if(op) a[i + j] = 1ll * a[i + j] * iv2 % mod, a[i + j + mid] = 1ll * a[i + j + mid] * iv2 % mod;
			}
}
void solve_xor(int *a, int *b, int *c) {
	FWT_xor(a, 0); FWT_xor(b, 0);
	for(int i = 0; i < n; i++) c[i] = 1ll * a[i] * b[i] % mod;
	FWT_xor(c, 1);
	for(int i = 0; i < n; i++)
		printf("%d ", c[i]);
	puts("");
}
int main() {
	static int ta[N], tb[N];
	iv2 = power(2, mod - 2);
	static int a[N], b[N], c[N];
	scanf("%d", &n); n = (1 << n);
	for(int i = 0; i < n; i++) scanf("%d", &ta[i]);
	for(int i = 0; i < n; i++) scanf("%d", &tb[i]);
	
	for(int i = 0; i < n; i++) a[i] = ta[i];
	for(int i = 0; i < n; i++) b[i] = tb[i];
	solve_or(a, b, c);
	
	for(int i = 0; i < n; i++) a[i] = ta[i];
	for(int i = 0; i < n; i++) b[i] = tb[i];
	solve_and(a, b, c);
	
	for(int i = 0; i < n; i++) a[i] = ta[i];
	for(int i = 0; i < n; i++) b[i] = tb[i];
	solve_xor(a, b, c);
	return 0;
}

NTT

const int N = 4e6 + 10, mod = 998244353;
int power(int x, int y) {
	int ret = 1;
	while(y) {
		if(y & 1) ret = 1ll * ret * x % mod;
		y >>= 1; x = 1ll * x * x % mod;
	}
	return ret;
}
namespace poly {
	int lim, le, id[N], ivlim, pre[N];
	void init(int n, int m) {
		lim = 1; while(lim <= n + m + 2) lim <<= 1, le++;
		ivlim = power(lim, mod - 2);		
		
		id[0] = 0; for(int i = 1; i < lim; i++) id[i] = id[i >> 1] >> 1 | ((i & 1) << (le - 1));
		pre[0] = 1;
		for(int mid = 1; mid < lim; mid <<= 1) {
			int wn = power(3, (mod - 1) / (mid << 1));
			for(int j = 0, w = 1; j < mid; j++, w = 1ll * w * wn % mod)
				pre[mid + j] = w;
		}
	}
	void NTT(int *a, int tp) {
		for(int i = 0; i < lim; i++)
			if(id[i] > i) swap(a[i], a[id[i]]);
		for(int mid = 1; mid < lim; mid <<= 1) {
			for(int i = 0, len = (mid << 1); i < lim; i += len) {
				for(int j = 0; j < mid; j++) {
					int x = a[i + j], y = 1ll * pre[mid + j] * a[i + j + mid] % mod;
					a[i + j] = (x + y) % mod;
					a[i + j + mid] = (x + mod - y) % mod;
				}
			}
		}
		if(tp) {
			for(int i = 0; i < lim; i++)
				a[i] = 1ll * a[i] * ivlim % mod;
			reverse(a + 1, a + lim);
		}
		return;
	}
	void getmul(int n, int m,int *f, int *g, int *h) {
		NTT(f, 0); NTT(g, 0);
		for(int i = 0; i < lim; i++) h[i] = 1ll * f[i] * g[i] % mod;
		NTT(h, 1);
		return;
	}
}
int main() {
	int n, m;
	static int f[N], g[N], h[N];
	scanf("%d%d", &n, &m);
	for(int i = 0; i <= n; i++) scanf("%d", &f[i]);
	for(int i = 0; i <= m; i++) scanf("%d", &g[i]);
	poly::init(n, m);
	poly::getmul(n, m, f, g, h);
	for(int i = 0; i <= n + m; i++)
		printf("%d ", h[i]);
	puts("");
	return 0;
}

多项式全家桶

const int N=4e6+10,mod=998244353;
inline int Add(int x,int y){ x+=y; if(x>=mod) x-=mod; return x; }
inline int Sub(int x,int y){ x-=y; if(x<0) x+=mod; return x; }
inline int mul(int x,int y){ return 1ll*x*y%mod; }
inline int read(){ char ch; ch=getchar(); int num=0,fff=1; while(ch<'0'||ch>'9'){ if(ch=='-') fff=-1; ch=getchar(); } while(ch>='0'&&ch<='9') num=(num<<3)+(num<<1)+ch-'0',ch=getchar(); return num*fff; }
inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>=10) write(x/10); putchar(x%10+'0'); return; }
inline int power(int a,int b){ int ret=1; while(b){ if(b&1) ret=mul(ret,a); b>>=1;a=mul(a,a); } return ret; }
inline int inv(int x){ return power(x,mod-2); }
namespace poly{
    int len,lim,id[N],pre[N],G=3,invG=332748118;
    inline void getlim(int x){ len=0,lim=1; while(lim<x) lim<<=1,len++; }
    inline void initid(){ for(int i=0;i<lim;i++) id[i]=(id[i>>1]>>1)|((i&1)<<(len-1)); }
    void initpre(){
        for(int i=1;i<lim;i<<=1){
            int w=power(3,(mod-1)/(i<<1)); pre[i]=1;
            for(int j=1;j<i;j++) pre[i+j]=mul(pre[i+j-1],w);
        } 
    }
    void NTT(int *a,bool tp){
        for(int i=0;i<lim;i++) if(i<id[i]) swap(a[i],a[id[i]]);
        for(int mid=1,cnt=0;mid<lim;mid<<=1,cnt++)
            for(int j=0,len=mid<<1;j<lim;j+=len)
                for(int k=0;k<mid;k++){
                    int x=a[j+k],y=mul(pre[mid+k],a[j+k+mid]);
                    a[j+k]=Add(x,y); a[j+k+mid]=Sub(x,y);
                }
        if(tp) return;
        int invlim=inv(lim);
        for(int i=0;i<lim;i++) a[i]=mul(a[i],invlim);
        reverse(a+1,a+lim);
        return;
    }
    inline void getmul(int n,int m,int *a,int *b){
        getlim(n+m); initid();
        NTT(a,1); NTT(b,1);
        for(int i=0;i<lim;i++) a[i]=mul(a[i],b[i]);
        NTT(a,0);
        return;
    }
    inline void getinv(int n,int *a,int *b){
        static int tmp[N];
        getlim(n<<1);
        int m=lim;
        for(int i=0;i<lim;i++) b[i]=0;
        b[0]=inv(a[0]);
        for(int step=2;step<m;step<<=1){
            getlim(step<<1); 
            for(int i=0;i<lim;i++) tmp[i]=(i<step)?a[i]:0;
            initid();
            NTT(tmp,1); NTT(b,1);
            for(int i=0;i<lim;i++) b[i]=mul(Sub(2,mul(b[i],tmp[i])),b[i]);
            NTT(b,0);
            for(int i=step;i<lim;i++) b[i]=0;
        }
        return;
    }
    inline void getdao(int n,int *a,int *b){ b[n-1]=0; for(int i=1;i<n;i++) b[i-1]=mul(i,a[i]); }
    inline void getjifen(int n,int *a,int *b){ b[0]=0; for(int i=1;i<n;i++) b[i]=mul(inv(i),a[i-1]); }
    inline void getln(int n,int *a,int *b){
        static int A[N],B[N];
        for(int i=0;i<lim;i++) A[i]=B[i]=b[i]=0; 
        getlim(n<<1); getdao(n,a,A);
        getinv(n,a,B); getmul(n,n,A,B);
        getjifen(n,A,b);
    }
    void getexp(int n,int *a,int *b){
        a[0]++;
        static int tmp[N];
        getlim(n<<1);
        int m=lim;
        for(int i=0;i<m;i++) tmp[i]=0;
        b[0]=1; 
        for(int step=2;step<m;step<<=1){
            getlim(step<<1); getln(step,b,tmp);
            for(int i=0;i<step;i++) tmp[i]=Sub(a[i],tmp[i]);
            getmul(step,step,b,tmp);
            for(int i=step;i<lim;i++) b[i]=tmp[i]=0;
        }
        a[0]--;
    }
    void getsqrt(int n,int *a,int *b){
        static int tmp[N],tmp2[N];
        int m=lim;
        for(int i=0;i<m;i++) tmp[i]=tmp2[N]=0;
        b[0]=1; 
        for(int step=2;step<m;step<<=1){
            getlim(step<<1); getinv(step,b,tmp);
            for(int i=0;i<step;i++) tmp2[i]=a[i];
            getmul(step,step,tmp,tmp2);
            int inv2=inv(2); for(int i=0;i<step;i++) b[i]=mul(Add(b[i],tmp[i]),inv2);
            for(int i=step;i<lim;i++) b[i]=tmp[i]=tmp2[i]=0;
        }
        return;
    }
    void getpower(int n,int k,int *a,int *b){
        static int tmp[N];
        getln(n,a,tmp);
        for(int i=0;i<n;++i) tmp[i]=mul(tmp[i],k);
        getexp(n,tmp,b);
    }
    void getdiv(int n,int m,int *a,int *b,int *c,int *d){
        static int ar[N],br[N],tmp[N];
        for(int i=0;i<n;i++) ar[i]=a[n-1-i];
        for(int i=0;i<m;i++) br[i]=b[m-1-i],tmp[i]=b[i];
        for(int i=n-m+1;i<lim;i++) ar[i]=0,br[i]=0;
        getinv(n-m+1,br,c);
        
        getmul(n,n-m+1,c,ar);
        reverse(c,c+n-m+1);
        for(int i=n-m+1;i<lim;i++) c[i]=0;
        for(int i=0;i<n-m+1;i++) d[i]=c[i];
        getmul(n-m+1,m,d,tmp);
        for(int i=0;i<m-1;i++) d[i]=Sub(a[i],d[i]);
        return;
    }
}
posted @ 2025-10-20 11:39  ACwisher  阅读(15)  评论(1)    收藏  举报