一坨模板

我谔谔,好像重复了几个。

目录:

  1. 并查集
  2. 树状数组
  3. 行列式求值
  4. 矩阵
  5. FHQ-Treap
  6. 快速幂
  7. 组合数
  8. 逆元
  9. 线段树(区改区查)
  10. 倍增求lca
  11. kruskal重构树
  12. 笛卡尔树
  13. 可持久化Trie
  14. 主席树:
  • 单点修改+单点查询
  • 区间第 \(k\)
  • 区改区查
  1. 高斯消元
  2. 点分治
  3. 树链剖分
  4. 最短路
  • floyd
  • dijkstra
  • spfa
  1. tarjan
  • 缩点
  • 割点
  • 割边
  1. lca
  • 另:求三个点的最短距离
  • 树上差分
  1. 中国剩余定理
  • BSGS
  1. 最小生成树
  2. 欧拉函数
  3. 线性筛
  4. dinic求网络最大流
  5. 费用流(lfy的)
    话说什么时候才能自己打费用流啊喂。
  6. 高维前缀和
  7. CDQ 分治
  8. 整体二分
  9. 考试用的简易对拍
  10. 线性基
  11. 后缀排序
  12. 求 height 数组

1.并查集

struct Disjoint_Set_Union
{
	int fa[N];
	int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
	void clear(){F(i,1,n) fa[i]=i;}
	void merge(int x,int y)
	{
		int u=find(x);
		int v=find(y);
		if(u!=v) fa[u]=v;
	}
}dsu;

2.树状数组

struct arr_tree
{
	int t[N];
	int lowbit(int x){return x&(-x);}
	void update(int x,int y){for(;x<=siz;x+=lowbit(x)) t[x]+=y;}//siz为值域范围
	int ask(int x)
	{
		int res=0;
		for(;x;x-=lowbit(x)) res+=t[x];
		return res;
	}
	il void clear(){F(i,0,n) t[i]=0;}
}T;

3.行列式求值

复杂度 \(O(n^2\log n + n^3)\)

int a[N][N];
il int sol()
{
	int res=1,w=1;
	F(i,1,n)
	{ 
		F(j,i+1,n)
		{
    		while(a[i][i])
			{
     	    	int div=a[j][i]/a[i][i];
        		F(k,i,n) a[j][k]=(a[j][k]-div*a[i][k]%mod+mod)%mod;
        		sd swap(a[i],a[j]);w=-w;
    		}
    		sd swap(a[i],a[j]);w=-w;
		}
	}
	for(int i=1;i<=n;i++) res=a[i][i]*res%mod;
	res=w*res;
	return (res+mod)%mod;
}

4.矩阵

具体情况需要具体修改。

struct M
{
	int a[N][N];
	il void clear(){me(a,0);}
	il void init(){F(i,1,n) a[i][i]=1;}
	int* operator [](int x){return a[x];}
	void Swap(int x,int y){F(i,1,n) sd swap(a[x][i],a[y][i]);}//交换两行 
	void Mul(int x,int k){F(i,1,n) a[x][i]=(a[x][i]*k%mod+mod)%mod;}//把某行乘上k 
	void Md(int x,int y,int k){F(i,1,n) a[x][i]=((a[x][i]+(a[y][i]*k%mod))%mod+mod)%mod;}//把某行的k倍乘到另一行上 
    il M operator*(M t)
	{
	    M res;
	    F(i,1,n) F(j,1,n) res.a[i][j]=0;
	    F(i,1,n) F(j,1,n) F(k,1,n) res.a[i][j]=(res.a[i][j]+a[i][k]*t.a[k][j]%mod)%mod;
    	return res;
	}
    il M operator^(int k)
	{
        M res,_=*this;
		res.init();
        while(k)
		{
            if(k&1)res=res*_;
            _=_*_;
            k>>=1;
        }
        return res;
        
    }
};

5.FHQ-Treap

#include<bits/stdc++.h>
#define sd std::
#define int long long
#define inf 0x3f3f3f3f
#define linf 1e18
#define il inline
#define db double
#define ldb long double
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define f(i,a,b) for(int i=(a);i>=(b);i--)
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)
#define me(x,y) memset(x,y,sizeof x)
#define pii sd pair<int,int>
#define umap(x,y) sd unordered_map<x,y>
#define pque(x) sd priority_queue<x>
#define X first
#define Y second
#define kg putchar(' ')
#define Fr(a) for(auto it:a)
#define dbg(x) sd cout<<#x<<": "<<x<<sd endl
il int read(){int w=1,c=0;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return w*c;}
void printt(int x){if(x>9) printt(x/10);putchar(x%10+48);}
il void print(int x){if(x<0) putchar('-'),printt(-x);else printt(x);}
il void put(int x){print(x);putchar('\n');}
il void printk(int x){print(x);kg;}
const int N=1e5+10;
int n;
struct FHQ
{
	struct node
	{
		int key,pri,siz;
		int ls,rs;
	}t[N];
	#define key(k) t[k].key
	#define pri(k) t[k].pri
	#define ls(k) t[k].ls
	#define rs(k) t[k].rs
	#define siz(k) t[k].siz
	int size=0,rt=0;//size为结点个数,rt为根
	void updrt(int u)//更新以 u 为根的Treap的大小
	{
		siz(u)=siz(ls(u))+siz(rs(u))+1;
	}
	void split(int u,int x,int &L,int &R)
	{
		if(!u)
		{
			L=R=0;
			return;
		}
		if(key(u)<=x) L=u,split(rs(u),x,rs(u),R);
		else R=u,split(ls(u),x,L,ls(u));
		updrt(u);
	}
	int merge(int L,int R)
	{
		if(!L||!R) return L+R;
		if(pri(L)>pri(R))
		{
			rs(L)=merge(rs(L),R);
			updrt(L);
			return L;
		}
		else
		{
			ls(R)=merge(L,ls(R));
			updrt(R);
			return R;
		}
	}
	void mknwnd(int x)
	{
		++size;
		siz(size)=1;
		ls(size)=rs(size)=0;
		key(size)=x,pri(size)=rand();
	}
	int insert(int x)
	{
		int L,R;
		split(rt,x,L,R);
		mknwnd(x);
		rt=merge(merge(L,size),R);
		return size;
	}
	int del(int x)
	{
		int L,M,R;
		split(rt,x,L,R);
		split(L,x-1,L,M);
		M=merge(ls(M),rs(M));
		rt=merge(merge(L,M),R);
		return rt;
	}
	int delall(int x)//删除所有值为 x 的结点
	{
		int L,M,R;
		split(rt,x,L,R);
		split(L,x-1,L,M);
		rt=merge(L,R);
		return rt;
	}
	int getrank(int x)
	{
		int L,R,res;
		split(rt,x-1,L,R);
		res=siz(L)+1;
		rt=merge(L,R);
		return res;
	}
	int kth(int u,int k)
	{
		if(k==siz(ls(u))+1) return u;
		if(k<=siz(ls(u))) return kth(ls(u),k);
		return kth(rs(u),k-siz(ls(u))-1);
	}
	//前驱
	int getpre(int x)
	{
		int L,R,res;
		split(rt,x-1,L,R);
		res=key(kth(L,siz(L)));
		rt=merge(L,R);
		return res;
	}
	//后继
	int getsuf(int x)
	{
		int L,R,res;
		split(rt,x,L,R);
		res=key(kth(R,1));
		rt=merge(L,R);
		return res;
	}
}Treap;
il void solve()
{
	n=read();
	while(n--)
	{
		int op=read(),x=read();
		if(op==1) Treap.insert(x);
		if(op==2) Treap.del(x);
		if(op==3) put(Treap.getrank(x));
		if(op==4) put(Treap.key(Treap.kth(Treap.rt,x)));
		if(op==5) put(Treap.getpre(x));
		if(op==6) put(Treap.getsuf(x));
	}
}
signed main()
{
	int T=1;
//	T=read();
	while(T--) solve();
    return 0;
}

6.快速幂

int ksm(int p,int q)
{
	if(!q) return 1;
	if(q&1) return p*ksm(p,q-1)%mod;
	int tmp=ksm(p,q/2)%mod;
	return tmp*tmp%mod;
}

无递归版本:

int ksm(int a,int b)
{
	int res=1;
	for(;b;b>>=1,a=a*a%mod) if(b&1) res=res*a%mod;
	return res;
}

7.组合数

  • 常见方法

适用范围:\(n\)\(m\) 较小。

时间复杂度:\(O(m)\)

依据性质:$$\operatorname{C}_nm=\operatorname{C}_n$$$$C_n^m=\frac{n!}{m!(n-m)!}$$

int C(int n,int m)
{
    if(m<0||n<m)return 0;
    if(m>n-m)m=n-m;
    int i,up=1,down=1;
	F(i,0,m-1)
    {
        up=up*(n-i)%mod;
        down=down*(i+1)%mod;
    }
    return up*inv(down)%mod;
}
  • 预处理

适用范围:\(n\)\(m\) 在 \(10^7\) 以内,\(mod\) 为质数

时间复杂度:预处理 \(O(n)\),调用 \(O(1)\)

int jc[N],inv[N];
void prework(int n)
{
    inv[0]=jc[0]=inv[1]=1;
    F(i,1,n) jc[i]=jc[i-1]*i%mod;
    F(i,2,n) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    F(i,1,n) inv[i]=inv[i-1]*inv[i]%mod;
}
int C(int n,int m)
{
    if(n<m)return 0;
    return jc[n]*inv[m]%mod*inv[n-m]%mod;
}
  • 杨辉三角

适用范围:\(n\)\(m\) 在 \(10^3\) 左右。

时间复杂度:预处理 \(O(n^2)\),调用 \(O(1)\)

空间复杂度:\(O(n^2)\)

int c[N][N];
il void prework(int n)
{
    F(i,1,n) F(j,0,i)
        if(!j)c[i][j]=1;
        else c[i][j]=c[i-1][j]+c[i-1][j-1];
}
  • lucas 定理

适用范围:\(n\)\(m\) 在 \(10^{18}\) 以内,\(mod\) 为 \(10^5\) 以内的质数。

时间复杂度:\(O(mod\times \log⁡ n)\)

int lucas(int a,int b)
{
    if(a<mod&&b<mod)return C(a,b);
    return C(a%mod,b%mod)*lucas(a/mod,b/mod)%mod;
}

8.逆元

  • 扩展欧几里得

时间复杂度:\(O(\log⁡ n)\)

int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x=1,y=0;
        return a;
    }
    int gcd=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return gcd;
}
il int inv(int a)
{
    int x,y;
    exgcd(a,mod,x,y);
    return (x%mod+mod)%mod;
}
  • 费马小定理

适用范围:\(mod\) 为质数,\(a\) 与 \(mod\) 互质。

时间复杂度:\(O(\log⁡ n)\)

il int qpow(int a,int b,int mod)
{
    int res=1;
    while(b)
    {
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
inline int inv(int a)
{
    return qpow(a,mod-2,mod);
}
  • 递推

适用范围:\(mod\) 为质数。

时间复杂度:预处理 \(O(n)\),调用 \(O(1)\)

void get_ny(int n)
{
    inv[0]=inv[1]=1;
    F(i,2,n) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}

9.线段树(区改区查)

{
	int s[N<<2],lazy[N<<2];
	#define ls k<<1
	#define rs k<<1|1
	void pushup(int k)
	{
		s[k]=s[ls]+s[rs];
		return;
	}
	void pushdown(int k,int l,int r)
	{
		if(!lazy[k]) return;
		int mid=l+r>>1;
		s[ls]+=(mid-l+1)*lazy[k];
		lazy[ls]+=lazy[k];
		s[rs]+=(r-mid)*lazy[k];
		lazy[rs]+=lazy[k];
		lazy[k]=0;
	}
	void built(int k,int l,int r)
	{
		if(l==r) return s[k]=a[l],void();
		int mid=l+r>>1;
		built(ls,l,mid);
		built(rs,mid+1,r);
		pushup(k);
	}
	void update(int k,int l,int r,int x,int y,int v)
	{
		if(x<=l&&y>=r)
		{
			s[k]+=(r-l+1)*v;
			lazy[k]+=v;
			return;
		}
		pushdown(k,l,r);
		int mid=l+r>>1;
		if(x<=mid) update(ls,l,mid,x,y,v);
		if(y>mid) update(rs,mid+1,r,x,y,v);
		pushup(k);
	}
	int ask(int k,int l,int r,int x,int y)
	{
		if(x<=l&&y>=r) return s[k];
		pushdown(k,l,r);
		int mid=l+r>>1;
		int res=0;
		if(x<=mid) res+=ask(ls,l,mid,x,y);
		if(y>mid) res+=ask(rs,mid+1,r,x,y);
		return res;
	}
}T;

10.倍增求lca

int dep[N],f[N][logN],vis[N];
void pre(int u,int fa)
{
    vis[u]=1;
    dep[u]=dep[fa]+1;
    f[u][0]=fa;
    F(i,0,20) f[u][i+1]=f[f[u][i]][i];
    for(int i=head[u];i;i=a[i].nex)
    {
        int v=a[i].to;
        if(vis[v]) continue;
        pre(v,u);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y]) sd swap(x,y);
    f(i,20,0)
    {
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        if(x==y) return x;
    }
    f(i,20,0)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}

11.kruskal 重构树

int n,m,cnt;
struct edge{int u,v,dis;}e[N];
bool cmp(edge a,edge b){return a.dis>b.dis;}
struct node{int to,nex;}a[N];
int head[N],tot;
int val[N],ff[N],vis[N];
int fa[N],top[N],son[N];
int siz[N],dep[N];
struct dcr_tree
{
    void add(int u,int to)
    {
        a[++tot].nex=head[u];
        a[tot].to=to;
        head[u]=tot;
    }
    int find(int x)
    {
        if(x==ff[x])return x;
        else return ff[x]=find(ff[x]);
    }
    void dfs1(int u,int pa)
    {
        siz[u]=1;
        vis[u]=1;
        for(int i=head[u];i;i=a[i].nex)
        {
            int to=a[i].to;
            if(to==pa) continue;
            dep[to]=dep[u]+1; fa[to]=u;
            dfs1(to,u);
            siz[u]+=siz[to];
            if(siz[to]>siz[son[u]])son[u]=to;
        }
    }
    void dfs2(int u,int tp)
    {
        top[u]=tp;
        if(son[u])dfs2(son[u],tp);
        for(int i=head[u];i;i=a[i].nex)
        {
            int v=a[i].to;
            if(v==fa[u]||v==son[u])continue;
            dfs2(v,v);
        }
    }
    void kruskal()
    {
        sd sort(e+1,e+1+m,cmp);
        F(i,1,n) ff[i]=i;
        F(i,1,m)
        {
            int x=find(e[i].u),y=find(e[i].v);
            if(x!=y)
            {
                val[++cnt]=e[i].dis;
                ff[cnt]=ff[x]=ff[y]=cnt;
                add(x,cnt);add(cnt,x);
                add(y,cnt);add(cnt,y);
            }
        }
        F(i,1,cnt) if(!vis[i])
        {
            int f=find(i);
            dfs1(f,0);
            dfs2(f,f);
        }
    }
    int lca(int u,int v)
    {
        while(top[u]!=top[v])
        {
            if(dep[top[u]]>dep[top[v]])u=fa[top[u]];
            else v=fa[top[v]];
        }
        return dep[u]<dep[v]?u:v;
    }
}T;

12.笛卡尔树

//下标满足二叉树性质,权值满足小根堆性质 
struct dct_tree
{
    int a[N],fa[N],ls[N],rs[N];//a数组为权值
    int s[N],top;//单调栈维护最右链 
    void init()
    {
        s[++top]=1;
    }
    void built()
    {
        init();
        F(i,2,n)
        {
            while(top&&a[s[top]]>a[i]) top--;//找到第一个<a[i]的值 
            if(!top) ls[i]=s[top+1];
            else ls[i]=rs[s[top]],rs[s[top]]=i;
            s[++top]=i;
        }
    }
    void tra_mid(int x)//中序遍历 
    {
        printk(x);
        if(ls[x]) tra_mid(ls[x]);
        if(rs[x]) tra_mid(rs[x]);
    }
}T;

13.可持久化Trie

这道题 的代码中的模板,其他题需要微调。

int s[N],a[N];
struct Trie
{
	int t[N*M][2],tag[N*M],root[N],tot=0;
	void insert(int x,int k)
	{
		int q=root[k],p=root[k-1];
		f(i,23,0)
		{
			int c=(x>>i)&1;
			if(t[p][0]) t[q][0]=t[p][0];
			if(t[p][1]) t[q][1]=t[p][1];
			t[q][c]=++tot;
			tag[tot]=k;
			p=t[p][c];
			q=t[q][c];
		}
	}
	int query(int l,int r,int x)
	{
		int p=root[r],ans=0;
		f(i,23,0)
		{
			int c=(x>>i)&1;
			if(t[p][!c]&&tag[t[p][!c]]>=l) {
				ans+=1<<i;
				p=t[p][!c];
			}
			else p=t[p][c];
		}
		return ans;
	}
}T;

14.主席树

  • 单点修改+区间查询:
    `
int a[N];
struct pst_tree
{
	struct node
	{
		int l,r;
		int val;
	}t[N<<5];
	int root[N],tot=0;
	#define l(i) t[i].l
	#define r(i) t[i].r
	#define val(i) t[i].val
	int newly(int k)
	{
		t[++tot]=t[k];
		return tot;
	}
	int built(int k,int l,int r)
	{
		k=++tot;
		if(l==r) return t[k].val=a[l],tot;
		int mid=l+r>>1;
		l(k)=built(l(k),l,mid);
		r(k)=built(r(k),mid+1,r);
		return k;
	}
	int update(int k,int l,int r,int x,int v)
	{
		k=newly(k);
		if(l==r) return val(k)=v,k;
		int mid=l+r>>1;
		if(x<=mid) l(k)=update(l(k),l,mid,x,v);
		else r(k)=update(r(k),mid+1,r,x,v);
		return k;
	}
	int query(int k,int l,int r,int x)
	{
		if(l==r) return val(k);
		int mid=l+r>>1;
		if(x<=mid) return query(l(k),l,mid,x);
		return query(r(k),mid+1,r,x);
	}
}T;
单点修改(a[x]=y):T.root[i]=T.update(T.root[k],1,n,x,y);
区间查询:T.query(T.root[k],1,n,x),T.root[i]=T.root[k];
  • 区间第 \(k\) 小:
//第 i 棵线段树的区间[x,y]就代表a[1]~a[i]中数字[x,y]值域内出现了几次。
struct pst_tree
{
	struct node
	{
		int l,r;
		int val;
	}t[N<<5];
	int root[N],tot=0;
	#define l(i) t[i].l
	#define r(i) t[i].r
	#define val(i) t[i].val
	int newly(int k)
	{
		t[++tot]=t[k];
		val(tot)++;
		return tot;
	}
	int built(int k,int l,int r)
	{
		k=++tot;
		if(l==r) return k;
		int mid=l+r>>1;
		l(k)=built(l(k),l,mid);
		r(k)=built(r(k),mid+1,r);
		return k;
	}
	int update(int k,int l,int r,int x)
	{
		k=newly(k);
		if(l==r) return k;
		int mid=l+r>>1;
		if(x<=mid) l(k)=update(l(k),l,mid,x);
		else r(k)=update(r(k),mid+1,r,x);
		return k;
	}
	int query(int l,int r,int x,int y,int z)
	{
		if(l==r) return l;
		int val=val(l(y))-val(l(x));
		int mid=l+r>>1;
		if(val>=z) return query(l,mid,l(x),l(y),z);
		else return query(mid+1,r,r(x),r(y),z-val);
	}
}T;
存数:T.root[i]=T.update(T.root[i-1],1,cnt,t),t是离散化之后的a[i]
输出:第k小的下标即为T.query(1,cnt,T.root[x-1],T.root[y],z)
il void solve()
{
	n=read(),m=read();
	F(i,1,n) a[i]=b[i]=read();
	sd sort(b+1,b+1+n);
	int cnt=sd unique(b+1,b+1+n)-b-1;
	T.root[0]=T.built(0,1,cnt);
	F(i,1,n)
	{
		int t=sd lower_bound(b+1,b+1+cnt,a[i])-b;//离散化
		T.root[i]=T.update(T.root[i-1],1,cnt,t);
	}
	F(i,1,m)
	{
		int x=read(),y=read(),z=read();
		put(b[T.query(1,cnt,T.root[x-1],T.root[y],z)]);
	}
}
  • 区改区查:
int update(int k,int l,int r,int x,int y,int v)
{
	k=newly(k);
	val(k)+=(MIN(r,y)-MAX(l,x)+1)*v;
	if(x<=l&&y>=r)
	{
		lazy(k)+=v;
		return k;
	}
	int mid=l+r>>1;
	if(x<=mid) l(k)=update(l(k),l,mid,x,y,v);
	if(y>mid) r(k)=update(r(k),mid+1,r,x,y,v);
	return k;
}
int query(int k,int l,int r,int x,int y,int laz)//laz即标记
{
	if(x<=l&&y>=r) return val(k)+(r-l+1)*laz;
	int mid=l+r>>1,res=0;
	if(x<=mid) res+=query(l(k),l,mid,x,y,laz*lazy(k));
	if(y>mid) res+=query(r(k),mid+1,r,x,y,laz*lazy(k));
	return res;
}

15.高斯消元

void Gauss()
{
	F(i,1,n)
	{
		ma=i;
		F(j,1,n)
		{
			if(fabs(a[j][j])>eps&&j<i) continue;
			if(fabs(a[j][i])>fabs(a[ma][i])) ma=j;
		}
		F(j,1,n+1) swap(a[i][j],a[ma][j]);
		if(fabs(a[i][i])<eps) continue;
		F(j,1,n)
		{
			if(i==j) continue;
			db rate=a[j][i]/a[i][i];
			F(k,i,n+1) a[j][k]-=a[i][k]*rate;
		}
	}
}
  • 异或消元
void Gauss()
{
	F(i,0,n-1)
	{
		ma=i;
		F(j,0,n-1)
		{
			if(a[j][j]&&j<i) continue;
			if(abs(a[j][i])>abs(a[ma][i])) ma=j;
		}
		F(j,0,n) sd swap(a[i][j],a[ma][j]);
		if(!a[i][i]) continue;
		F(j,0,n-1)
		{
			if(i==j) continue;
			if(!a[j][i]) continue;
			F(k,i,n) a[j][k]^=a[i][k];
		}
	}
}

16.点分治

  • 求树上是否有一条边权和为 \(k\) 的路径。
#include<bits/stdc++.h>
#define inf 2e9
#define linf 1e18
//#define int long long
#define db double
#define ldb long double
#define sd std::
#define il inline
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define f(i,a,b) for(int i=(a);i>=(b);i--)
#define MAX(x,y) (x>y?x:y)
#define MIN(x,y) (x<y?x:y)
#define me(x,y) memset(x,y,sizeof x)
#define umap(x,y) sd unorded_map<x,y>
#define pque(x) sd priority_queue<x>
#define pii sd pair<int,int>
#define X first
#define Y second
#define kg putchar(' ')
#define Fr(a) for(auto it:a)
#define dbg(x) sd cout<<#x<<":"<<"\n"
il int read(){int w=1,c=0;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return w*c;}
void printt(int x){if(x>9) printt(x/10);putchar(x%10+48);}
il void print(int x){if(x<0) putchar('-'),x=-x;printt(x);}
il void printk(int x){print(x);kg;}
il void put(int x){print(x);puts("");}
const int N=1e5+10;
int n,m;
struct node
{
	int nex;
	int to;
	int dis;
}a[N<<1];
int q[N];
int head[N],tot;
void add(int u,int v,int w)
{
	a[++tot].nex=head[u];
	head[u]=tot;
	a[tot].to=v;
	a[tot].dis=w;
}
int siz[N],weigh[N],vis[N],ans[N];
int root;
void dfs1(int u,int fa,int sum)//求重心 
{
	weigh[u]=0,siz[u]=1;//weigh[u]为u为根子树中子树最大的节点 
	for(int i=head[u];i;i=a[i].nex)
	{
		int v=a[i].to;
		if(v==fa||vis[v]) continue;
		dfs1(v,u,sum);
		siz[u]+=siz[v];
		weigh[u]=MAX(weigh[u],siz[v]);
	}
	weigh[u]=MAX(weigh[u],sum-siz[u]);
	if(weigh[u]<weigh[root]) root=u;
	
}
int dis[N],cnt,d[N];//d和dis数组本质上是一样的,但d数组的下标是时间戳,cnt是时间戳 
void dfs2(int u,int fa)
{
	d[++cnt]=dis[u];
	for(int i=head[u];i;i=a[i].nex)
	{
		int v=a[i].to;
		if(vis[v]||v==fa) continue;
		dis[v]=dis[u]+a[i].dis;
		dfs2(v,u);
	}
}
void get_ans(int u,int val)//val表示加或者减 
{
	cnt=0;
	dfs2(u,0);
	sd sort(d+1,d+1+cnt);
	F(i,1,m)
	{
		int s=0,l=1,r=cnt;
		while(l<r)
		{
			if(d[l]+d[r]<=q[i]) s+=r-l,++l;
			else r--;
		}
		l=1,r=cnt;
		while(l<r)
		{
			if(d[l]+d[r]<q[i]) s-=r-l,++l;
			else r--;
		}
		ans[i]+=s*val;
	}
}
void gat_ans(int u)
{
	dis[u]=0;
	vis[u]=1;
	get_ans(u,1);
	for(int i=head[u];i;i=a[i].nex)
	{
		int v=a[i].to;
		if(vis[v]) continue;
		dis[v]=a[i].dis;
		get_ans(v,-1);
		root=0;
		dfs1(v,u,siz[v]);
		gat_ans(root);
	}
}
il void solve()
{
	n=read(),m=read();weigh[0]=n;
	F(i,1,n-1)
	{
		int x=read(),y=read(),z=read();
		add(x,y,z);add(y,x,z);
	}
	F(i,1,m) q[i]=read();
	dfs1(1,0,n);
	gat_ans(root);
	F(i,1,m) puts(ans[i]?"AYE":"NAY");
}
int main()
{
	int T=1;
//	T=read();
	while(T--) solve();
	return 0;
}

17.树链剖分

软件包管理器的操作有 \(u\to v\) 路径的,所以就放这个。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
const int N=200100;
struct node
{
    int nex;
    int to;
}a[N];
int tot,head[N];
int fa[N],dep[N],size[N];
int son[N],top[N];
int id[N],rev[N],t;
int s[N<<1],lazy[N<<1];//区间和 
int ans;
int n,m;
void built(int k,int l,int r)
{
	if(l==r)
	{
		lazy[k]=-1;
		s[k]=0;
		return;
	}
	int mid=l+r>>1;
	built(k<<1,l,mid);
	built(k<<1|1,mid+1,r);
}
void add(int u,int v)
{
    a[++tot].nex=head[u];
    head[u]=tot;
    a[tot].to=v;
}
void dfs1(int u,int da)
{
    size[u]=1;
    fa[u]=da;
    dep[u]=dep[da]+1;
    for(int i=head[u];i;i=a[i].nex)
    {
        int v=a[i].to;
        if(v==da) continue;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int da)
{
    id[u]=++t;
    top[u]=da;
    if(!son[u]) return;
    dfs2(son[u],da);
    for(int i=head[u];i;i=a[i].nex)
    {
    	int v=a[i].to;
    	if(v==fa[u]||v==son[u]) continue;
    	dfs2(v,v);
	}
}
void pushdown(int k,int l,int r)
{
    if(lazy[k]==-1) return;
    int mid=(l+r)>>1;
    s[k<<1]=(mid-l+1)*lazy[k];
    lazy[k<<1]=lazy[k];
    s[k<<1|1]=(r-mid)*lazy[k];
    lazy[k<<1|1]=lazy[k];
    lazy[k]=-1;
}
void update(int k,int l,int r,int x,int y,int v)
{
    if(y<l||x>r) return;
    if(x<=l&&y>=r)
    {
        s[k]=(r-l+1)*v;
        lazy[k]=v;
        return;
    }
    pushdown(k,l,r);
    int mid=(l+r)>>1;
    update(k<<1,l,mid,x,y,v);
    update(k<<1|1,mid+1,r,x,y,v);
    s[k]=s[k<<1]+s[k<<1|1];
}
int ask(int k,int l,int r,int x,int y)
{
    if(y<l||x>r) return 0;
    if(x<=l&&y>=r) return s[k];
    pushdown(k,l,r);
    int mid=(l+r)>>1;
    return ask(k<<1,l,mid,x,y)+ask(k<<1|1,mid+1,r,x,y);
}
void lca(int u,int v)
{
    int fu=top[u],fv=top[v];
    while(fu!=fv)
    {
        if(dep[fu]<dep[fv])
        {
            std::swap(u,v);
            std::swap(fu,fv);
        }
        update(1,1,n,id[fu],id[u],1);
        u=fa[fu];
        fu=top[u];
    }
    if(dep[u]>dep[v]) std::swap(u,v);
    update(1,1,n,id[u],id[v],1);
}
void init()
{
    dfs1(1,0);
    dfs2(1,1);
    built(1,1,n);
}
int x;
std::string op;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        scanf("%d",&x);
        add(x+1,i+1);
        add(i+1,x+1);
    }
    init();
    scanf("%d",&m);
    while(m--)
    {
        std::cin>>op;
        scanf("%d",&x);x++;
        int ff=ask(1,1,n,1,n);
        if(op[0]=='i')
        {
            lca(1,x);
            printf("%d\n",abs(ff-ask(1,1,n,1,n)));
        }
        else
        {
            update(1,1,n,id[x],id[x]+size[x]-1,0);
            printf("%d\n",abs(ff-ask(1,1,n,1,n)));
        }
    }
}

18.最短路

  • floyd
for(int k=1;k<=n;k++)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j];
        }
    }
}
  • dijkstra
struct edge{int v,w;};
struct node{int dis,u;bool operator > (const node& a) const{return dis>a.dis;}};
vector<edge> e[N];
int dis[maxn],vis[N];
priority_queue<node>q;
void dijkstra(int n,int s)
{
    memset(dis,0x3f3f3f3f,sizeof(dis));
    dis[s]=0;
    q.push({0,s});
    while(!q.empty())
    {
        int u=q.top().u;
        q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(auto ed:e[u])
        {
            int v=ed.v,w=ed.w;
            if(dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                q.push({dis[v],v});
            }
        }
    }
}
  • spfa

判断是否有负环

int spfa_dfs(int u)
{
    vis[u]=1;
    for(int k=f[u];k!=0;k=e[k].next)
    {
        int v=e[k].v;
        int w=e[k].w;
        if(d[u]+w<d[v])
        {
            d[v]=d[u]+w;
            if(!vis[v])
                if(spfa_dfs(v)) return 1;
            else return 1;
        }
    }
    vis[u]=0;
    return 0;
}

19.tarjan

  • 缩点
#include<cstdio>
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
const int N=1e6+10;
struct node
{
    int nex;
    int to;
}a[N];
int tot,head[N];
int num,dfn[N],low[N];//时间戳 
int top,s[N],vis[N];//栈 
int cnt,scc[N],size[N];//强连通分量的个数,强连通分量,每个强连通分量的元素个数 
void add(int u,int v)
{
    a[++tot].nex=head[u];
    head[u]=tot;
    a[tot].to=v;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++num;
    vis[u]=1,s[++top]=u;
    for(int i=head[u];i;i=a[i].nex)
    {
        int v=a[i].to;
        if(!dfn[v])//树枝边 
        {
            tarjan(v);
            low[u]=min(low[v],low[u]);
        }
        else if(vis[v]) low[u]=min(low[u],dfn[v]);//后向边,横叉边 
    }
    if(dfn[u]==low[u])
    {
        cnt++;
        int y;
        do
        {
            y=s[top--];
            vis[y]=0;
            scc[y]=cnt;
            size[cnt]++;
        }while(u!=y)
    }
}
  • 割点(vis[u]=1u 为割点)
void tarjan(int u)
{
    dfn[u]=low[u]=++num;
    for(int i=head[u];i!=-1;i=a[i].nex)
    {
        int v=a[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
            if(dfn[u]<=low[v])
            /*割点判定1:x 不为树根,存在树枝边 (x,y)(x 为 y 的父亲),如果满足:
            dfn[x]<=low[y],x就是割点。*/
            {
                if(u!=st&&dfn[v]<=dfn[ed]) vis[u]=1;
            }
        }
        else
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
}
  • 割边(ans 即为割边个数)
void tarjan(int x,int fa)
{
    low[x]=dfn[x]=++num;
    for(int i=head[x];i!=-1;i=a[i].nex)
    {
        int v=a[i].to;
        if(!dfn[v])
        {
            tarjan(v,x);
            low[x]=min(low[x],low[v]);
            if(dfn[x]<low[v]) ans++;
        }
        else if(v!=fa)
        {
            low[x]=min(low[x],dfn[v]);
        }
    }
}

20.LCA

void pre(int u,int fa)
{
    vis[u]=1;
    dep[u]=dep[fa]+1;
    f[u][0]=fa;
    for(int i=0;i<20;i++) f[u][i+1]=f[f[u][i]][i];
    for(int i=head[u];i;i=a[i].nex)
    {
        int v=a[i].to;
        if(vis[v]) continue;
        pre(v,u);
    }
}
int lca(int x,int y)
{
    if(dep[x]<dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
    {
        if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        if(x==y) return x;
    }
    for(int i=20;i>=0;i--)
    {
        if(f[x][i]!=f[y][i])
        {
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}
  • 求三个点的最短距离
cin>>x>>y>>z;
int lc1=lca(x,y),lc2=lca(y,z),lc3=lca(x,z);
if(lc1==lc2&&lc2==lc3) cout<<lc1<<" "<<dep[x]+dep[y]+dep[z]-dep[lc3]-(dep[lc1]*2)<<endl;
else if(lc1==lc2) cout<<lc3<<" "<<dep[x]+dep[y]+dep[z]-dep[lc3]-(dep[lc1]*2)<<endl;
else if(lc1==lc3) cout<<lc2<<" "<<dep[x]+dep[y]+dep[z]-dep[lc2]-(dep[lc1]*2)<<endl;
else cout<<lc1<<" "<<(dep[x]+dep[y]+dep[z])-dep[lc1]-(dep[lc2]*2)<<endl;
  • 树上差分
int l=lca(x,y);//x~y都+1
d[x]++;
d[y]++;
d[l]--;
d[f[l][0]]--;

统计:

void dfs(int u,int fa)
{
    for(int i=head[u];i;i=a[i].nex)
    {
        int v=a[i].to;
        if(v==fa) continue;
        dfs(v,u);
        d[u]+=d[v];
    }
    ans=max(ans,d[u]);
}

主函数中:

dfs(1,0)

21.中国剩余定理

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,A[11],B[11];
ll Exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    ll ans=Exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return ans;
}

ll china()
{
    ll lcm=1,d,y,x=0;
    for(int i=1;i<=n;i++) lcm*=A[i];
    for(int i=1;i<=n;i++)
    {
        ll w=lcm/A[i];
        d=Exgcd(A[i],w,d,y);
        x=(x+y*w*B[i])%lcm;
    }
    return (x+lcm)%lcm;
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>A[i]>>B[i];
    cout<<china();
    return 0;
}
  • BSGS
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll BSGS(ll a,ll b,ll m)
{
    unordered_map<ll,ll> hs;//map会比这个多一个log的复杂度 
    hs.clear();
    ll cur=1,t=sqrt(m)+1;
    for(int B=1;B<=t;B++)
    { 
        (cur*=a)%=m;
        hs[b*cur%m]=B;
    }
    ll now=cur;
    for(int A=1;A<=t;A++)
    {
        auto it=hs.find(now);
        if(it!=hs.end()) return A*t-it->second;
        (now*=cur)%=m;
    }
    return -1;
}
ll m,a,b; 
int main()
{
    ios::sync_with_stdio(0);
    cin>>m>>a>>b;
    int p=BSGS(a,b,m);
    if(p==-1) cout<<"no solution";
    else cout<<p;
    return 0;
}

22.最小生成树

#include<algorithm>
#include<cstdio>
#define int long long
const int N=1e6+10;
int fa[N];
int n,m;
struct node
{
    int to;
    int nex;
    int dis;
}a[N];
bool cmp(node a,node b){return a.dis<b.dis;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int ans,cnt;
void add(int u,int v,int w)
{
    a[++m].nex=u;
    a[m].to=v;
    a[m].dis=w;
}
void kruskal()
{
    for(int i=1;i<=m;i++)
    {
        int u=find(a[i].nex);
        int v=find(a[i].to);
        if(u==v) continue;
        ans+=a[i].dis;
        cnt++;
        fa[u]=v;
        if(cnt==n-1) return printf("%lld",ans),void();
    }
    puts("-1");
}
int x;
signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
    {
        scanf("%lld",&x);
        if(x) add(i,j,x);
    }
    for(int i=1;i<=n;i++) fa[i]=i;
    std::sort(a+1,a+1+m,cmp);
    kruskal();
}

23.欧拉函数

求的是小于n的正整数中与n互质的数的数目

注意 \(n=1\) 时这个值为 \(1\)

#define ull unsigned long long
ull ans;
ull init(ull n)
{
    for(ull i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            ans=ans/i*(i-1); 
            while(n%i==0) n/=i;
        }
    }
    if(n>1) ans=ans/n*(n-1); 
    return ans;
}

24.线性筛

void pri() 
{
    //p[i]:能整除i的最小质数,为0表示i是质数 
    F(i,2,N)
    {
        if(!p[i]) pri[++cnt]=i;
        for(int j=1;pri[j]*i<=N;j++)
        {
            p[i*pri[j]]=pri[j];
            if(!(i%pri[j])) break;
        }
    }
}

25.dinic求网络最大流

#include<bits/stdc++.h>
#define sd std::
#define int long long
#define inf 0x3f3f3f3f
#define linf 1e18
#define il inline
#define db double
#define ldb long double
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define f(i,a,b) for(int i=(a);i>=(b);i--)
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)
#define me(x,y) memset(x,y,sizeof x)
#define pii sd pair<int,int>
#define umap(x,y) sd unordered_map<x,y>
#define pque(x) sd priority_queue<x>
#define X first
#define Y second
#define kg putchar(' ')
#define Fr(a) for(auto it:a)
#define dbg(x) sd cout<<#x<<": "<<x<<sd endl
il int read(){int w=1,c=0;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return w*c;}
void printt(int x){if(x>9) printt(x/10);putchar(x%10+48);}
il void print(int x){if(x<0) putchar('-'),printt(-x);else printt(x);}
il void put(int x){print(x);putchar('\n');}
il void printk(int x){print(x);kg;}
const int N=1e5+10;
struct node
{
	int nex;
	int to;
	int w;
}a[N];
int tot=1,head[N],now[N];
void add(int u,int v,int w)
{
	a[++tot].nex=head[u];
	head[u]=tot;
	a[tot].to=v;
	a[tot].w=w;
}
int d[N];//d为层数 
int n,m,s,t;
int bfs()
{
	me(d,0);
	sd queue<int> q;
	q.push(s);
	d[s]=1;
	now[s]=head[s];
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i;i=a[i].nex)
		{
			int v=a[i].to,w=a[i].w;
			if(w>0&&!d[v])
			{
				d[v]=d[u]+1;
				now[v]=head[v];
				if(v==t) return 1;
				q.push(v);
			}
		}
	}
	return 0;
}
int dfs(int u,int flow)
{
	if(u==t) return flow;
	int tmp=flow;
	for(int i=now[u];i&&tmp;i=a[i].nex)
	{
		int v=a[i].to,w=a[i].w;
		now[u]=i;
		if(d[u]+1==d[v]&&w)
		{
			int k=dfs(v,MIN(tmp,w));
			if(!k) d[v]=0;
			a[i].w-=k;
			a[i^1].w+=k;
			tmp-=k;
		}
	}
	return flow-tmp;
}
il void solve()
{
	n=read(),m=read(),s=read(),t=read();
	F(i,1,m)
	{
		int x=read(),y=read(),z=read();
		add(x,y,z);
		add(y,x,0);
	}
	int ans=0;
	while(bfs()) ans+=dfs(s,INT_MAX);
	return put(ans);
}
signed main()
{
	int T=1;
//	T=read();
	while(T--) solve();
    return 0;
}

费用流

#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)a[i]=read()
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
int read()
{
    char ch=getchar();
    int r=0,w=1;
    while(ch<'0'||ch>'9') w=ch=='-'?-1:w,ch=getchar();
    while(ch>='0'&&ch<='9') r=r*10+ch-'0',ch=getchar();
    return r*w;
}
CI N=1e5+5,INF=0x3f3f3f3f3f3f3f3f;
int n,m,s,t,cst,tot=1,vis[N],dis[N],now[N],head[N];
struct edge
{
	int to,nex,flow,data;
}e[N<<1];
void add(int x,int y,int f,int z)
{
	e[++tot].to=y;
	e[tot].flow=f;
	e[tot].data=z;
	e[tot].nex=head[x];
	head[x]=tot;
}
bool spfa()
{
	std::queue<int> q;
	mem(dis,0x3f);
	memcpy(now,head,sizeof now);
	q.push(s);
	dis[s]=0;
	vis[s]=1;
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		vis[x]=0;
		erg(i,x) {
			int y=e[i].to,z=e[i].data;
			if(e[i].flow<=0) continue;
			if(dis[y]>dis[x]+z) {
				dis[y]=dis[x]+z;
				if(!vis[y]) {
					q.push(y);
					vis[y]=1;
				}
			}
		}
	}
	return dis[t]!=INF;
}
int dfs(int x,int flow)
{
	if(x==t) return flow;
	vis[x]=1;
	int tmp=flow;
	for(int i=now[x];i&&tmp;i=e[i].nex)
	{
		int y=e[i].to,z=e[i].data;
		if(!e[i].flow||dis[y]!=dis[x]+z||vis[y]) continue;
		int k=dfs(y,std::min(tmp,e[i].flow));
		cst+=k*z;
		e[i].flow-=k;
		e[i^1].flow+=k;
		tmp-=k;
	}
	vis[x]=0;
	return flow-tmp;
}
int mcmf()
{
	int ans=0;
	while(spfa())
	{
		ans+=dfs(s,INF);
	}
	return ans;
}
signed main()
{
	n=read(),m=read(),s=read(),t=read();
	rep(i,1,m)
	{
		int x=read(),y=read(),f=read(),z=read();
		add(x,y,f,z);
		add(y,x,0,-z);
	}
	std::cout<<mcmf()<<" "<<cst;
    return 0;
}

27.高维前缀和

对于所有的 \(0\le i\le 2^n-1\),求解 \(\sum \limits_{j\subset i} a_j\)

F(j,0,n-1) F(i,0,(1<<n)-1) if(i>>j&1) f[i]+=f[i^(1<<j)];

28.CDQ分治

#include<algorithm>
#include<cstdio>
#define sd std::
#define int long long
#define inf 0x3f3f3f3f
#define linf 1e18
#define il inline
#define db double
#define ldb long double
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define f(i,a,b) for(int i=(a);i>=(b);i--)
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)
#define me(x,y) memset(x,y,sizeof x)
#define pii sd pair<int,int>
#define umap(x,y) sd unordered_map<x,y>
#define pque(x) sd priority_queue<x>
#define X first
#define Y second
#define kg putchar(' ')
#define Fr(a) for(auto it:a)
#define dbg(x) sd cout<<#x<<": "<<x<<sd endl
il int read(){int w=1,c=0;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return w*c;}
void printt(int x){if(x>9) printt(x/10);putchar(x%10+48);}
il void print(int x){if(x<0) putchar('-'),printt(-x);else printt(x);}
il void put(int x){print(x);putchar('\n');}
il void printk(int x){print(x);kg;}
const int N=2e5+10;
int n,k;
struct arr_tree
{
	int s[N];
	il int lowbit(int x)
	{
		return x&(-x);
	}
	il void update(int x,int y)
	{
		for(;x<=k;x+=lowbit(x)) s[x]+=y;
	}
	il int ask(int x)
	{
		int res=0;
		for(;x;x-=lowbit(x))
		{
			res+=s[x]; 
		}
		return res;
	}
}T;
struct node
{
	int a,b,c,cnt,sum;
}x[N],q[N];
int s[N],p[N];
bool cmp1(node a,node b)
{
	if(a.a!=b.a) return a.a<b.a;
	if(a.b!=b.b) return a.b<b.b;
	return a.c<b.c;
}
bool cmp2(node a,node b)
{
	if(a.b!=b.b) return a.b<b.b;
	return a.c<b.c;
}
int tot,cnt;
void init()//进行排序离散化等 
{
	sd sort(x+1,x+1+n,cmp1);
	F(i,1,n)
	{
		cnt++;
		if(x[i].a!=x[i+1].a||x[i].b!=x[i+1].b||x[i].c!=x[i+1].c)
		{
			q[++tot].a=x[i].a;
			q[tot].b=x[i].b;
			q[tot].c=x[i].c;
			q[tot].cnt=cnt;
			cnt=0;
		}
	}
}
il void solve(int l,int r)
{
	if(l==r) return;
	int mid=l+r>>1;
	solve(l,mid);
	solve(mid+1,r);
	sd sort(q+l,q+mid+1,cmp2);
	sd sort(q+mid+1,q+r+1,cmp2);
	int i=l,j=mid+1;//双指针 
	while(j<=r)
	{
		while(i<=mid&&q[i].b<=q[j].b)
		{
			T.update(q[i].c,q[i].cnt);
			i++;
		}
		q[j].sum+=T.ask(q[j].c);
		j++;
	}
	F(k,l,i-1) T.update(q[k].c,-q[k].cnt);
}
int ans[N];
il void solve()
{
	n=read();k=read();
	F(i,1,n) x[i].a=read(),x[i].b=read(),x[i].c=read();
	init();
	solve(1,tot);
	F(i,1,tot) ans[q[i].sum+q[i].cnt-1]+=q[i].cnt;
	F(i,0,n-1) put(ans[i]);
}
signed main()
{
    int T=1;
//    T=read();
    while(T--) solve();
    return 0;
}

29.整体二分

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#define sd std::
//#define int long long
#define inf 0x3f3f3f3f
#define linf 1e18
#define il inline
#define db double
#define ldb long double
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define f(i,a,b) for(int i=(a);i>=(b);i--)
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)
#define me(x,y) memset(x,y,sizeof x)
#define pii sd pair<int,int>
#define umap(x,y) sd unordered_map<x,y>
#define pque(x) sd priority_queue<x>
#define X first
#define Y second
#define kg putchar(' ')
#define Fr(a) for(auto it:a)
#define dbg(x) sd cout<<#x<<": "<<x<<sd endl
il int read(){int w=1,c=0;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return w*c;}
void printt(int x){if(x>9) printt(x/10);putchar(x%10+48);}
il void print(int x){if(x<0) putchar('-'),printt(-x);else printt(x);}
il void put(int x){print(x);putchar('\n');}
il void printk(int x){print(x);kg;}
const int N=1e6+10;
int n,m;
int a[N];
struct arr_tree
{
	int s[N];
	il int lowbit(int x){return x&(-x);}
	il void update(int x,int y){for(;x<=n;x+=lowbit(x)) s[x]+=y;}
	il int ask(int x){int res=0;for(;x;x-=lowbit(x)){res+=s[x];}return res;}
}T;
struct query
{
	int l,r,k;
	int id;
	int val;
	int op;//op=0表这是数据,op=1代表这是询问 
}q[N],q1[N],q2[N];//q1q2用来暂时储存第一类和第二类询问 
int ans[N];
void solve(int ql,int qr,int l,int r)//l和r为答案区间,ql和qr为询问区间 
{
	if(ql>qr) return; 
	if(l==r)
	{
		F(i,ql,qr) if(q[i].op) ans[q[i].id]=l;//赋值 
		return;
	}
	int mid=l+r>>1;
	int c1=0,c2=0;//两种类型的询问的个数 
	F(i,ql,qr)
	{
		if(!q[i].op)
		{
			if(q[i].r<=mid) T.update(q[i].id,1),q1[++c1]=q[i];
			else q2[++c2]=q[i];
		}
		else
		{
			int ans=T.ask(q[i].r)-T.ask(q[i].l-1);
			if(ans>=q[i].k) q1[++c1]=q[i];
			else q2[++c2]=q[i],q2[c2].k-=ans;
		}
	}
	F(i,ql,qr) if(!q[i].op&&q[i].r<=mid) T.update(q[i].id,-1);//清空树状数组 
	F(i,1,c1) q[ql+i-1]=q1[i];
	F(i,1,c2) q[ql+i+c1-1]=q2[i];
	solve(ql,ql+c1-1,l,mid);
	solve(ql+c1,qr,mid+1,r);
}
il void solve()
{
	n=read(),m=read();
	F(i,1,n) q[i].r=read(),q[i].id=i,q[i].op=0;
	F(i,1,m) q[i+n].l=read(),q[i+n].r=read(),q[i+n].k=read(),q[i+n].id=i,q[i+n].op=1;
	solve(1,n+m,-inf,inf);
	F(i,1,m) put(ans[i]);
}
int main()
{
    int T=1;
//    T=read();
    while(T--) solve();
    return 0;
}

30.对拍

#include<bits/stdc++.h>
using namespace std;
int main() {
	int tot=0,k;
	scanf("%d",&k);
	while(k--) {
		system("mkdata.exe");
		system("AC.exe");
		double st=clock();
		system("WA.exe");
		double ed=clock();
		if(!system("fc AC.out WA.out"))printf("第%d个测试点:Accepted,用时:%.2lfms\n",++tot,ed-st);
		else {
			printf("第%d个测试点:Wrong Answer \n",++tot);
			break;
		}
	}
	return 0;
}

31.线性基

int d[N];//线性基 
void insert(int x)
{
	f(i,55,0)
	{
		if(!(x&(1ll<<i))) continue;
		if(d[i]) x^=d[i];
		else
		{
			d[i]=x;
			break;
		}
	}
}

32.后缀排序

#include<bits/stdc++.h>
#define sd std::
//#define int long long
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define f(i,a,b) for(int i=(a);i>=(b);i--)
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)
#define me(x,y) memset(x,y,sizeof x)
#define pii sd pair<int,int>
#define X first
#define Y second
#define Fr(a) for(auto it:a)
int read(){int w=1,c=0;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return w*c;}
void printt(int x){if(x>9) printt(x/10);putchar(x%10+48);}
void print(int x){if(x<0) putchar('-'),printt(-x);else printt(x);}
void put(int x){print(x);putchar('\n');}
void printk(int x){print(x);putchar(' ');}
const int N=5e5+10;
int n,p,V;
char s[N];
int sa[N],id[N],ork[N],rk[N],cnt[N],height[N];
void solve()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	F(i,1,n) cnt[rk[i]=s[i]]++;
	V=128;
	F(i,1,V) cnt[i]+=cnt[i-1];
	f(i,n,1) sa[cnt[rk[i]]--]=i;
	
	for(int w=1;;w<<=1,V=p)
	{
		int cur=0;
		F(i,n-w+1,n) id[++cur]=i;
		F(i,1,n) if(sa[i]>w) id[++cur]=sa[i]-w;
		
		F(i,1,V) cnt[i]=0;
		F(i,1,n) cnt[rk[i]]++;
		F(i,1,V) cnt[i]+=cnt[i-1];
		f(i,n,1) sa[cnt[rk[id[i]]]--]=id[i];
		F(i,1,n) ork[i]=rk[i];
		p=0;
		F(i,1,n)
		{
			if(ork[sa[i]]==ork[sa[i-1]]&&ork[sa[i]+w]==ork[sa[i-1]+w])
			{
				rk[sa[i]]=p;
			}
			else rk[sa[i]]=++p;
		}
		if(p==n) break;
	}
	F(i,1,n) printk(sa[i]);
}
int main()
{
	int T=1;
//	T=read();
	while(T--) solve();
    return 0;
}

33.求 height 数组

#include<bits/stdc++.h>
#define sd std::
//#define int long long
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define f(i,a,b) for(int i=(a);i>=(b);i--)
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)
#define me(x,y) memset(x,y,sizeof x)
#define pii sd pair<int,int>
#define X first
#define Y second
#define Fr(a) for(auto it:a)
int read(){int w=1,c=0;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return w*c;}
void printt(int x){if(x>9) printt(x/10);putchar(x%10+48);}
void print(int x){if(x<0) putchar('-'),printt(-x);else printt(x);}
void put(int x){print(x);putchar('\n');}
void printk(int x){print(x);putchar(' ');}
const int N=5e5+10;
int n,p,V;
char s[N];
int sa[N],id[N],ork[N],rk[N],cnt[N],height[N];
void solve()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	F(i,1,n) cnt[rk[i]=s[i]]++;
	V=128;
	F(i,1,V) cnt[i]+=cnt[i-1];
	f(i,n,1) sa[cnt[rk[i]]--]=i;
	
	for(int w=1;;w<<=1,V=p)
	{
		int cur=0;
		F(i,n-w+1,n) id[++cur]=i;
		F(i,1,n) if(sa[i]>w) id[++cur]=sa[i]-w;
		
		F(i,1,V) cnt[i]=0;
		F(i,1,n) cnt[rk[i]]++;
		F(i,1,V) cnt[i]+=cnt[i-1];
		f(i,n,1) sa[cnt[rk[id[i]]]--]=id[i];
		F(i,1,n) ork[i]=rk[i];
		p=0;
		F(i,1,n)
		{
			if(ork[sa[i]]==ork[sa[i-1]]&&ork[sa[i]+w]==ork[sa[i-1]+w])
			{
				rk[sa[i]]=p;
			}
			else rk[sa[i]]=++p;
		}
		if(p==n) break;
	}
	F(i,1,n)
	{
		int k=height[rk[i-1]];
		if(k) k--;
		while(s[i+k]==s[sa[rk[i]-1]+k]) k++;
		height[rk[i]+1]=k;
	}
	F(i,1,n) printk(height[i]);
}
int main()
{
	int T=1;
//	T=read();
	while(T--) solve();
    return 0;
}
posted @ 2024-12-19 16:00  _E_M_T  阅读(10)  评论(0)    收藏  举报