模板库

ST表

for(int i=1;i<=N;i++){
		for(int j=1;j+(1<<i)-1<=n;j++){
			f[j][i]=max(f[j][i-1],f[j+(1<<i-1)][i-1]);
		}
	}
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		int len=log2(y-x+1);
		int ans=max(f[x][len],f[y-(1<<len)+1][len]);
		printf("%d\n",ans);
	}

割点

void tarjan(long long u,long long root){
	st[++top]=u;
	long long son=0;
	dfn[u]=low[u]=++visn;
	for(long long i=head[u];i;i=edge[i].next){
		long long to=edge[i].to;
		if(!dfn[to]){
			son++;
			tarjan(to,u);
			low[u]=min(low[u],low[to]);
			if((u==root&&son>1)||(root!=u&&low[to]>=dfn[u]))cut[u]=1;
		}
		low[u]=min(low[u],dfn[to]);
	}
}

2-SAT

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 4000007;
struct node{
	int to,next;
}edge[maxn*2];
int cnt,head[maxn];
void add(int from,int to){
	edge[++cnt].to=to;
	edge[cnt].next=head[from];
	head[from]=cnt;
}

int dfn[maxn],low[maxn],n,m,st[maxn],instack[maxn],visn,tot,top,co[maxn];

void tarjan(int u){
	dfn[u]=low[u]=++visn;
	st[++top]=u;
	instack[u]=1;
	for(int i=head[u];i;i=edge[i].next){
		int to=edge[i].to;
		if(!dfn[to]){
			tarjan(to);
			low[u]=min(low[u],low[to]);
		}
		else if(instack[to])low[u]=min(low[u],dfn[to]);
	}
	if(dfn[u]==low[u]){
		tot++;int t;
		do{
			t=st[top--];
			co[t]=tot;
			instack[t]=0;
		}while(t!=u);
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y,a,b;
		scanf("%d%d%d%d",&a,&x,&b,&y);
		if(x==1&&y==1){add(a,b+n),add(b,a+n);}
		if(x==1&&y==0){add(a,b),add(b+n,a+n);}
		if(x==0&&y==1){add(a+n,b+n),add(b,a);}
		if(x==0&&y==0){add(a+n,b),add(b+n,a);}
	}
	for(int i=1;i<=2*n;i++){
		if(!dfn[i])tarjan(i);
	}
	for(int i=1;i<=n;i++){
		if(co[i]==co[i+n]){
			puts("IMPOSSIBLE");
			return 0;
		}
	}
	puts("POSSIBLE");
	for(int i=1;i<=n;i++){
		if(co[i]>co[i+n])printf("1 ");
		else printf("0 ");
	}
	return 0;
}

裴蜀定理

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int n,ans;
int main(){
	scanf("%d%d",&n,&ans);
	for(int i=2;i<=n;i++){
		int x;scanf("%d",&x);
		ans=gcd(ans,abs(x));
	}
	cout<<ans;
}

线性递推逆元

	inv[1]=1;
	for(int i=2;i<=n;i++){
		inv[i]=((p-p/i)*inv[p%i])%p;
	}

拓展欧几里得

void exgcd(int a,int b,int &x,int &y){
	if(!b){
		x=1;
		y=0;
		return a;
	}int t=exgcd(b,a%b,x,y);
	int xx=x;
	x=y;
	y=xx-(a/b)*y;
}

NIM游戏

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int T,n;
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		int SG=0;
		for(int i=1;i<=n;i++){
			int x;
			scanf("%d",&x);SG^=x;
		}
		if(!SG)puts("No");
		else puts("Yes");
	}
	代码是可以无限取的SG(x)=x
	
	对于只能取m个的,SG(x)=x%(m+1);
	因为对于每一个(k+1)*(m+1),我们总可以使他变成k*(m+1) 
	当小于m+1时,就是无限制取法 
	
	对于只能取f={a1,a2,a3....an}个的
	我们使用集合的mex操作
	SG(x)=mex(x-f{a1,a2,a3...an}); 
	
	部分建模
	1.硬币翻转 ,每一个位置为i的朝上硬币,他的SG值就为i 
	2.阶梯,我们只考虑奇数级阶梯,因为偶数级阶梯,我们可以通过两次移动消除他的影响
	对于奇数级阶梯进行nim即可,SG值为石子数 
	3.ANTI-NIM游戏 当可决策集合为空时,为必败态。 
	先手必胜当且仅当:
    所有堆的石子数都为1且游戏的SG值为0
    有些堆的石子数大于1且游戏的SG值不为0
    4.使用mex函数打表找规律吧 
}

二叉堆

switch(a){
	case 1:q:cin>>b;q.push(0-b);break;
	case 2:cout<<0-q.top()<<endl;break;
	case 3:q.pop();break; 
}

缩点

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 10005;
struct node{int to,next,w;}edge[maxn*10];
int head[maxn],n,m,cnt=1,instack[maxn],dfn[maxn],low[maxn];
int stack[maxn],rd[maxn],num[maxn],sum[maxn],tot,co[maxn],top,visn=1,root[maxn];
long long int dp[maxn];
pair<int,int> g[10*maxn];
queue < int > q;
void add(int from,int to){
	edge[cnt].to=to;
	edge[cnt].next=head[from];
	head[from]=cnt++; 
}

void work(){
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=n;i++)cin>>num[i];
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		add(x,y);
		g[i].first=x;
		g[i].second=y;
	}
}
long long int tpsort(){
	for(int i=1;i<=n;i++){
		if(rd[i]==0&&co[i]==i)
		q.push(co[i]);
		dp[co[i]]=sum[co[i]];
	}
	while(!q.empty()){
		int f1=q.front();
		q.pop();
		for(int i=head[f1];i!=-1;i=edge[i].next){
			int to=edge[i].to;
			int w=edge[i].w;
			dp[to]=max(dp[f1]+sum[co[to]],dp[to]);
			if(--rd[to])q.push(to);
		}
	}
	long long ans=-1;
	for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
	return ans;
}
void tarjan(int u){
	stack[++top]=u;instack[u]=1;
	dfn[u]=low[u]=visn++;
	for(int i=head[u];i!=-1;i=edge[i].next){
		int v=edge[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[v],low[u]);
		}
		else if(instack[v])low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		int t;
		do{
			t=stack[top--];
			sum[u]+=num[t];
			instack[t]=0;
			co[t]=u;
		}while(t!=u);
	}
}
int main(){
	work();
	for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
	for(int i=1;i<=cnt;i++)edge[i].to=edge[i].next=0;
	cnt=1;
	memset(head,-1,sizeof(head));
	for(int i=1;i<=m;i++){
		int f1=g[i].first;
		int f2=g[i].second;
		if(co[f1]!=co[f2])
			add(co[f1],co[f2]);
	}
	cout<<tpsort();
	return 0;
}

负环

void spfa(){
	queue<int>q;
	for(int i=1;i<=n;i++){
		dis[i]=INF;
	}memset(vis,0,sizeof(vis));
    memset(getin,0,sizeof(getin));
	q.push(1);vis[1]=1;dis[1]=0;
	while(!q.empty()){
		int f1=q.front();q.pop();
		vis[f1]=0;
		for(int i=head[f1];i;i=edge[i].next){
			int to=edge[i].to;
			if(dis[to]>dis[f1]+edge[i].w){
				dis[to]=dis[f1]+edge[i].w;
				if(!vis[to]){
					getin[to]++;
					vis[to]=1;
					q.push(to);
				}
				if(getin[to]>n){
					puts("YE5");flag=false;
					return;
				}
			}
			
		}
	}
}

树链剖分

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 1e5+7;
typedef long long ll;
struct node{
    int l,r;
    ll sum,lazy;
    #define lazy(x) tr[x].lazy
    #define v(x) tr[x].sum
    #define lch(x) x<<1
    #define rch(x) x<<1|1
}tr[maxn*4];

struct no{
	int to,next;
}edge[maxn*4];
int cnt,head[maxn];
void add(int from,int to){
	edge[++cnt].to=to;
	edge[cnt].next=head[from];
	head[from]=cnt;
}

int n,m,r,mod,dfn[maxn];
int top[maxn],tot[maxn],sz[maxn],f[maxn],dep[maxn],son[maxn],num[maxn];

void pushup(int k){v(k)=(v(lch(k))+v(rch(k)))%mod;}
void pushdown(int k){
	if(lazy(k)){
		v(lch(k))=(v(lch(k))+lazy(k)*(tr[lch(k)].r-tr[lch(k)].l+1))%mod;
		v(rch(k))=(v(rch(k))+lazy(k)*(tr[rch(k)].r-tr[rch(k)].l+1))%mod;
		lazy(lch(k))=(lazy(lch(k))+lazy(k));
		lazy(rch(k))=(lazy(rch(k))+lazy(k));
		lazy(k)=0;
	}
}


void dfs1(int u,int fa){
	f[u]=fa;dep[u]=dep[fa]+1;sz[u]=1;
	for(int i=head[u];i;i=edge[i].next){
		int to=edge[i].to;
		if(to==fa)continue;
		dfs1(to,u);sz[u]+=sz[to];
		if(sz[son[u]]<sz[to])son[u]=to;
	}
}

void dfs2(int u,int ftop){
	dfn[u]=++dfn[0];
	tot[dfn[u]]=u;
	top[u]=ftop;
	if(!son[u])return;
	dfs2(son[u],ftop);
	for(int i=head[u];i;i=edge[i].next){
		int to=edge[i].to;
		if(!dfn[to])dfs2(to,to);
	}
}

void build(int k,int l,int r){
	tr[k].l=l;
	tr[k].r=r;
	if(l==r){
		v(k)=num[tot[l]];
		return;
	}
	int mid=l+r>>1;
	build(lch(k),l,mid);
	build(rch(k),mid+1,r);
	pushup(k);
}

void SegAdd(int k,int x,int y,ll sum){
	if(tr[k].l>=x&&tr[k].r<=y){
		v(k)=(v(k)+(tr[k].r-tr[k].l+1)*sum)%mod;
		lazy(k)=(lazy(k)+sum)%mod;
		return;
	}pushdown(k);
	int mid=tr[k].l+tr[k].r>>1;
	if(x<=mid)SegAdd(lch(k),x,y,sum);
	if(y>mid) SegAdd(rch(k),x,y,sum);
	pushup(k);
}

ll SegQuery(int k,int x,int y){
	if(tr[k].l>=x&&tr[k].r<=y)return v(k)%mod;
	pushdown(k);
	int mid=tr[k].l+tr[k].r>>1;ll ret=0;
	if(x<=mid) ret=(ret+SegQuery(lch(k),x,y))%mod;
	if(y>mid)  ret=(ret+SegQuery(rch(k),x,y))%mod;
	return ret;
} 

void TreeAdd(int st,int en,ll sum){
	while(top[st]!=top[en]){
		if(dep[top[st]]<dep[top[en]])swap(st,en);
		SegAdd(1,dfn[top[st]],dfn[st],sum);
		st=f[top[st]];
	}if(dep[st]>dep[en])swap(st,en);
	SegAdd(1,dfn[st],dfn[en],sum);
}

ll TreeQuery(int st,int en){
	ll ret=0;
	while(top[st]!=top[en]){
		if(dep[top[st]]<dep[top[en]])swap(st,en);
		ret=(ret+SegQuery(1,dfn[top[st]],dfn[st]))%mod;
		st=f[top[st]];
	}if(dep[st]>dep[en])swap(st,en);
	ret=(ret+SegQuery(1,dfn[st],dfn[en]))%mod;
	return ret;
}

int main(){
    scanf("%d%d%d%d",&n,&m,&r,&mod);
    for(int i=1;i<=n;i++){
		scanf("%d",&num[i]);
    } 
    for(int i=1;i<=n-1;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
    }
    dfs1(r,0);
    dfs2(r,r);
    build(1,1,dfn[0]);
    for(int i=1;i<=m;i++){
		int opt,x,y;ll z;
		scanf("%d%d",&opt,&x);
		if(opt==1){
			scanf("%d%lld",&y,&z);
			TreeAdd(x,y,z);
		}else if(opt==2){
			scanf("%d",&y);
			printf("%lld\n",TreeQuery(x,y));
		}else if(opt==3){
			scanf("%lld",&z);
			SegAdd(1,dfn[x],dfn[x]+sz[x]-1,z);
		}else{
			printf("%lld\n",SegQuery(1,dfn[x],dfn[x]+sz[x]-1));
		}
    }
    return 0;
}

Dinic

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 100007;
const int INF = 2147483647;
int n,m,s,t;
struct node{
	int to,next;
	ll flow;
}edge[maxn*4];
int cnt,head[maxn];
void add(int from,int to,ll w){
	edge[++cnt].to=to;
	edge[cnt].next=head[from];
	edge[cnt].flow=w;
	head[from]=cnt;
}
int dep[maxn],cur[maxn];
ll Dinic(int u,ll rest){
	ll ret=0,f=0;
	if(u==t||rest==0)return rest;
	for(int &i=cur[u];i!=-1;i=edge[i].next){
		node &e=edge[i];
		if(dep[e.to]==dep[u]+1 && (f=Dinic(e.to,min(rest,e.flow)))>0){
			e.flow-=f;
			edge[i^1].flow+=f;
			ret+=f;rest-=f;
			if(rest==0)return ret;
		}
	}
	return ret;
}
int vis[maxn];
bool spfa(){
	queue<int>q;
	memset(vis,0,sizeof(vis));
	q.push(s);vis[s]=1;dep[s]=1;
	while(!q.empty()){
		int f1=q.front();q.pop();
		for(int i=head[f1];i!=-1;i=edge[i].next){
			int to=edge[i].to;
			if(!vis[to]&&edge[i].flow>0){
				vis[to]=1;
				dep[to]=dep[f1]+1;
				q.push(to);
			}
		}
	}
	return vis[t];
}
void MF(){
	ll ans=0 ;
	while(spfa()){
		for(int i=1;i<=n;i++)cur[i]=head[i];
		ans+=Dinic(s,INF);
	}
	printf("%lld",ans);
}
int main(){
	memset(head,-1,sizeof(head));cnt=-1;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;i++){
		int x,y;ll z;scanf("%d%d%lld",&x,&y,&z);
		add(x,y,z);add(y,x,0);
	}
	MF();
}

矩阵快速幂

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 107;
const int mod = 1e9+7;
typedef long long ll;
struct M{
	int len;
	ll c[maxn][maxn];
	friend M operator*(M a,M b){
		M c;c.len=a.len;
		memset(c.c,0,sizeof(c.c));
		for(int i=1;i<=a.len;i++){
			for(int j=1;j<=a.len;j++){
				for(int l=1;l<=a.len;l++){
					c.c[i][j]=(c.c[i][j]+a.c[i][l]*b.c[l][j])%mod;
				}
			}
		}
		return c;
	}
};
int n;
ll k;
M POW(M a,ll times){
	if(times==1){
		return a; 
	}else {
		M ret=POW(a,times/2);
		ret=ret*ret;
		if(times%2)ret=ret*a;
		return ret;
	}
}
M st;
int main(){
	scanf("%d%lld",&n,&k);st.len=n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%lld",&st.c[i][j]);
		}
	}
	st=POW(st,k);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cout<<st.c[i][j]<<" ";
		}
		cout<<endl;
	}
} 

Lucas定理

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
ll p;
ll ksm(ll a,ll b){
	if(b==0)return 1;
	else{
		ll ret=ksm(a,b/2);
		ret=(ret*ret)%p;
		if(b%2)ret=(ret*a)%p;
		return ret;
	}
}
ll C(ll n,ll m){
	ll ret=1,ret2=1;
	for(ll i=n-m+1;i<=n;i++)ret=(ret*i)%p;
	for(ll i=1;i<=m;i++)ret2=(ret2*i)%p;
	return ret*ksm(ret2,p-2);
}

ll lucas(ll n,ll m){
	if(!n||!m)return 1;
	return (C(n%p,m%p)%p*lucas(n/p,m/p)%p)%p;
}
int main(){
	int T;
	scanf("%lld",&T);
	while(T--){
		ll n,m;
		scanf("%lld%lld%lld",&n,&m,&p);
		printf("%lld\n",lucas(n+m,m)%p);
	} 
}

AC自动机

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 5e6+7;
int ch[maxn][26],cnt;
int n,end[maxn];

void putin(string a){
	int root=0;
	for(int i=0;i<a.length();i++){
		if(!ch[root][a[i]-'a'])ch[root][a[i]-'a']=++cnt;
		root=ch[root][a[i]-'a'];
	}
	end[root]++;
}
int last[maxn],f[maxn];
void getfail(){
	queue<int>q;f[0]=0;
	for(int i=0;i<26;i++)
		if(ch[0][i])f[ch[0][i]]=0,q.push(ch[0][i]);
	while(!q.empty()){
		int now=q.front();q.pop();
		for(int i=0;i<26;i++){
			int u=ch[now][i];
			if(!u)ch[now][i]=ch[f[now]][i];
			else q.push(u),f[u]=ch[f[now]][i];
		}
	}
}
void find(string a){
	int len=a.length();
	int j=0,ans=0;
	for(int i=0;i<len;i++){
		j=ch[j][a[i]-'a'];
		for(int t=j;t&&~end[t];t=f[t])ans+=end[t],end[t]=-1;
	}
	cout<<ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		string into;
		cin>>into;
		putin(into);
	}
	getfail();
	string T;
	cin>>T;
	find(T);
	return 0;
}

倍增LCA

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 500007;
struct node{
	int to,next;
}edge[maxn*2];
int cnt,head[maxn];
void add(int from,int to){
	edge[++cnt].to=to;
	edge[cnt].next=head[from];
	head[from]=cnt;
}
int n,m,rt,f[maxn][21],dep[maxn];
void dfs(int u,int fa){
	dep[u]=dep[fa]+1;f[u][0]=fa;
	for(int i=1;i<=log2(dep[u]);i++)f[u][i]=f[f[u][i-1]][i-1];
	for(int i=head[u];i;i=edge[i].next){
		int to=edge[i].to;
		if(to==fa)continue;
		dfs(to,u);
	}
}

int LCA(int u,int v){
	if(dep[u]<dep[v])swap(u,v);
	for(int i=log2(dep[u]-dep[v]);i>=0;i--)
		if(dep[f[u][i]]>=dep[v])u=f[u][i];
	if(u==v)return u;
	for(int i=log2(dep[u]);i>=0;i--)
		if(f[u][i]^f[v][i])
			u=f[u][i],
			v=f[v][i];
	return f[u][0];
}

int main(){
	scanf("%d%d%d",&n,&m,&rt);
	for(int i=1;i<n;i++){
		int x,y;scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}dfs(rt,0);
	for(int i=1;i<=m;i++){
		int x,y;scanf("%d%d",&x,&y);
		printf("%d\n",LCA(x,y));
	}
	return 0;
}

权值线段树和线段树合并

// 并不会破坏原来的两棵树 


int merge(int u,int v){
    if(!u || !v) return u+v;
    int t=++cnt;
    sum[t]=sum[u]+sum[v];
    ls[t]=merge(ls[u],ls[v]);
    rs[t]=merge(rs[u],rs[v]);
    return t;
}

// 如果原树不在使用,我们可以把一棵树合并到另一颗上
// 可以节约不少空间

void merge(int &rt1,int &rt2,int l,int r){
	if(!rt1||!rt2){rt1+=rt2;return;}
	int mid=l+r>>1;
	if(l==r){tr[rt1].v=1;return;}
	merge(lch(rt1),lch(rt2),l,mid);
	merge(rch(rt1),rch(rt2),mid+1,r);
	pushup(rt1);
} 

LCT

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define lch(x) c[x][0]
#define rch(x) c[x][1]
using namespace std;
const int maxn = 300005;
int n,m,val[maxn],c[maxn][2],fa[maxn],s[maxn],lazy[maxn],st[maxn];
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
    do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
    return f*x;
}
void pushr(int k){swap(c[k][1],c[k][0]);lazy[k]^=1;}
bool notroot(int x) { return c[fa[x]][1]==x||c[fa[x]][0]==x; }
void pushdown(int k){
    if(lazy[k]){
        lazy[k]^=1;
        lazy[c[k][0]]^=1;
        lazy[c[k][1]]^=1;
        swap(c[k][0],c[k][1]);
    }
}
void pushup(int k){s[k]=s[lch(k)]^s[rch(k)]^val[k];}
void rotete(int x){
    int y=fa[x],z=fa[y],k=c[y][1]==x,w=c[x][!k];
    if(notroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
    if(w)fa[w]=y;fa[y]=x;fa[x]=z;
    pushup(y);
}
void splay(int x){
    int cnt=0,x1=x,y,z;
    st[++cnt]=x1;
    while(notroot(x1))st[++cnt]=x1=fa[x1];
    while(cnt)pushdown(st[cnt--]);
    while(notroot(x)){
        y=fa[x],z=fa[y];
        if(notroot(y))
            rotete((c[z][0]==y)^(c[y][0]==x)?x:y);
        rotete(x);
    }
    pushup(x);return ;
}
void access(int x){
    for(int y=0;x;y=x,x=fa[x])
        splay(x),c[x][1]=y,pushup(x);
    return;
}
void makeroot(int x){
    access(x);
    splay(x);
    lazy[x]^=1;
}
void split(int x,int y){
    makeroot(x);
    access(y);splay(y);
}
int findroot(int x){
    access(x);splay(x);
    while(lch(x))pushdown(x),x=lch(x);
    splay(x);return x;
}
void link(int x,int y){	
    makeroot(x);
    if(findroot(y)==x)return;
    fa[x]=y;
}
void cut(int x,int y){
    makeroot(x);
    if(findroot(y)==x&&fa[y]==x&&!c[y][0])
        fa[y]=c[x][1]=0,pushup(x);
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)val[i]=read();
    for(int i=1;i<=m;i++){
        int type,x,y;
        type=read(),x=read(),y=read();
        switch(type){
            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);val[x]=y,pushup(x);
        }
    }
    return 0;
}

最小生成树Kruskal

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn = 1000005;
int n,m;
struct node{
	int x,y;
	long long z;
}a[maxn];
int zu[maxn*2];
int find(int x){return zu[x]==x?x:zu[x]=find(zu[x]);}

void kruskal(){
	for(int i=1;i<=n;i++)zu[i]=i;
	int f1,f2,k=0;
	long long ans=0;
	for(int i=1;i<=m;i++){
		f1=find(a[i].x);
		f2=find(a[i].y);
		if(f1!=f2){
			zu[f1]=f2;k++;
			ans+=a[i].z;
		}
		if(k==n-1){
			cout<<ans;
			break;
		}
	}
}
bool comp(node a,node b){return a.z<b.z;}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	cin>>a[i].x>>a[i].y>>a[i].z;
	sort(a+1,a+m+1,comp);	
	kruskal();
}

Splay

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 101001;
const int INF = 2147483647;
int n,m,ch[maxn][2],root,fa[maxn],size[maxn],lazy[maxn];
void pushup(int x){size[x]=size[ch[x][0]]+size[ch[x][1]]+1;}

void pushdown(int x){
    if(lazy[x]){
        swap(ch[x][0],ch[x][1]);
        lazy[ch[x][0]]^=1;
		lazy[ch[x][1]]^=1;
		lazy[x]=0;
    }
}
void rotate(int x,int &k){
    int y=fa[x];
	int z=fa[y];
	int kind;
    if(ch[y][0]==x)kind=1;
	else kind=0;
    if(y==k)k=x;
    else{
		if(ch[z][0]==y)ch[z][0]=x;
	else ch[z][1]=x;
	}
    ch[y][kind^1]=ch[x][kind];fa[ch[y][kind^1]]=y;
    ch[x][kind]=y;fa[y]=x;fa[x]=z;
    pushup(x);pushup(y);
}
void splay(int x,int &k){
    while(x!=k){
        int y=fa[x];
		int z=fa[y];
        if(y!=k){
            if((ch[y][0]==x)^(ch[z][0]==y))rotate(x,k);
            else rotate(y,k);
        }
        rotate(x,k);
    }
}
int find(int x,int k){
    pushdown(x);
	int s=size[ch[x][0]];
    if(k==s+1)return x;
    if(k<=s)return find(ch[x][0],k);
    else return find(ch[x][1],k-s-1);
}
void work(int l,int r){
	int x=find(root,l);
	int y=find(root,r+2);
	splay(x,root);
	splay(y,ch[x][1]);
	lazy[ch[y][0]]^=1;
}
void build(int l,int r,int f){
    if(l>r)return;
    int mid=(l+r)/2;
    if(mid<f)ch[f][0]=mid;
	else ch[f][1]=mid;
    fa[mid]=f;size[mid]=1;
    if(l==r)return;
    build(l,mid-1,mid);
	build(mid+1,r,mid);
    pushup(mid);
}
int main()
{
	cin>>n>>m;
	root=(n+3)/2;
	build(1,n+2,root);
	for(int i=1;i<=m;i++){
		int l,r;
		cin>>l>>r;
		work(l,r);
	}
	for(int i=2;i<=n+1;i++)printf("%d ",find(root,i)-1);
}
//以下为splay维护treap
int get(int x){
    return son[fa[x]][1]==x;//如果它父节点的右儿子编号等于它那么返回1(右节点),否则返回0(是左节点)
}
void rotate(int x){
    int f=fa[x],ff=fa[f],w=get(x);//父节点、祖父节点、是父节点的左子树还是右子树
    son[f][w]=son[x][w^1];//x节点的另一个子树放给原本x节点的位置
    fa[son[f][w]]=f;//更新x节点的另一个子树的父节点
    son[x][w^1]=f;//将父节点接到x节点的另一个子树上
    fa[f]=x;
    fa[x]=ff;//f、x位置互换后更新祖父节点
    if(ff){//父节点不是根节点(根节点的父节点为0)
        son[ff][son[ff][1]==f]=x;
    }
    update(f);
    update(x);
}
void update(int x){
    if(x!=0){//如果是根节点,旋转时种类数始终不变
        siz[x]=cnt[x];//自身值的出现次数
        if(son[x][0])//如果有左子树
            siz[x]+=siz[son[x][0]];
        if(son[x][1])//如果有右子树
            siz[x]+=siz[son[x][1]];
    }
}
void splay(int x){
    for(int f;f=fa[x];rotate(x)){//注意旋转的始终是x
        if(fa[f]){//可能存在三点一线
            rotate(get(x)==get(f)?f:x);//三点一线情况判断
        }
    }
}
void insect(int v){
    if(sz==0){//如果这棵树是空树,插入点应该为根节点
        sz++;
        son[1][1]=son[1][0]=fa[1]=0;
        siz[1]=cnt[1]=1;
        root=1;
        key[1]=v;
        return;
    }
    int now=root,f=0;//now表示现在查找到节点编号,f表示当前节点的父节点
    while(1){
        if(key[now]==v){//如果这个值已经在树中,那么它出现的次数增加
            cnt[now]++;
            update(now);//更新相关点
            update(f);
            splay(now);//将插入的点旋转到根节点,便于下一次可能的操作
            break;
        }
        f=now;
        now=son[now][v>key[now]];//依照节点值查找位置,如果大于当前值v>key[now]=1,则在右子树范围内,反之亦然
        if(now==0){//树中无这个值,查找到树的底端,新建一个子节点
            sz++;//新节点编号
            son[sz][1]=son[sz][0]=0;//新节点初始化
            fa[sz]=f;
            siz[sz]=cnt[sz]=1;
            son[f][v>key[now]]=sz;//判断新节点是左节点还是右节点并更新父节点
            key[sz]=v;
            update(f);//更新数量
            splay(sz);//旋转到根节点
            break;
        }
    }
}
int find(int v){
    int ans=0,now=root;//ans记录已经有多少比它小的点,now表示正在寻找的节点的编号
    while(1){
        if(v<key[now]){//如果当前节点的值大于v,那么当前节点的左子树不完全小于v,继续向当前节点的左子树寻找
            now=son[now][0];
        }
        else{//当前节点的左子树上的值必然全部小于v
            ans+=(son[now][0]!=0?siz[son[now][0]]:0);//如果有左子树则直接加上左子树的数量
            if(v==key[now]){//如果当前节点的值等于v,则右子树上不可能有比它小的数,所有比它小的数已经找完
                splay(now);//下一次可能的操作
                return ans+1;//有1个数比它小那么它应该是第2,以此类推,要+1
            }
            ans+=cnt[now];//key[now]<v的情况,除了它的左儿子还要加上它自身的数量
            now=son[now][1];//右子树中可能存在比v小的值,所以在右子树中继续寻找
        }
    }
}
int findx(int x){
    int now=root;//当前节点
    while(1){
        if(son[now][0]!=0&&siz[son[now][0]]>=x){//如果左子树的数量大于x,就是说第x个是在左子树上(前提是有左子树)
            now=son[now][0];//在左子树上接着搜索
        }
        else{//第x个在以当前节点为顶点的树中
            int less=(son[now][0]!=0?siz[son[now][0]]:0)+cnt[now];//左子树的数量(可能没有)+当前节点的值的数量
            if(x<=less)//由于之前判断过是否在左子树上,并且在之后的运算中排除了所有左子树,x却不在右子树上,那么只可能是当前点的值
                return key[now];
            x-=less;//在右子树中还有多少值比它小,排除左子树
            now=son[now][1];//继续搜索
        }
    }
}
int query_pre(int x){
   splay(x);//首先旋转到根节点方便查找
    int now=son[root][0];//定位左子树
    while(son[now][1]!=0)now=son[now][1];//循环查找左子树中最右边的点
    return now;//最底部跳出循环,找到答案
}
int query_next(int x){
    splay(x);
    int now=son[root][1];
    while(son[now][0]!=0)now=son[now][0];
    return now;
}
void clear(int x){
    son[x][0]=son[x][1]=fa[x]=siz[x]=key[MX]=cnt[x]=0;
}
void del(int v){
    find(v);
    if(cnt[root]>1){//第一种情况
        cnt[root]--;
        update(root);
        return;
    }
    if(son[root][0]==0&&son[root][1]==0){//第二种情况
        clear(root);
        root=0;//将树清空
        return;
    }
    if(son[root][0]==0){//第三种情况
        int old=root;
        root=son[root][1];
        fa[root]=0;//新根的父节点更新
        clear(old);
        return;
    }
    if(son[root][1]==0){//第四种情况
        int old=root;
        root=son[root][0];
        fa[root]=0;
        clear(old);
        return;
    }
    int newroot=query_per(root),oldroot=root;
    splay(newroot);//将新根转上来
    fa[son[oldroot][1]]=newroot;
    son[root][1]=son[oldroot][1];//继承右子树
    clear(oldroot);//旧根归零
    update(root);//更新新根
}

线段树

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100007;
typedef long long ll;

struct node{
	ll val;
	int l,r,length;
	#define v(x) tr[x].val
	#define lch(x) x<<1
	#define rch(x) x<<1|1
	#define lc(x) tr[x].l
	#define rc(x) tr[x].r
}tr[maxn*4];
ll addlazy[maxn*4],mullazy[maxn*4],val[maxn],mod;
int n,m;
void pushup(int k){v(k)=v(lch(k))+v(rch(k))%mod;}
void pushdown(int k){
	v(lch(k))=(v(lch(k))*mullazy[k])%mod;
	v(lch(k))=(v(lch(k))+addlazy[k]*tr[lch(k)].length)%mod;
	v(rch(k))=(v(rch(k))*mullazy[k])%mod;
	v(rch(k))=(v(rch(k))+addlazy[k]*tr[rch(k)].length)%mod;
	addlazy[lch(k)]=(addlazy[lch(k)]*mullazy[k]+addlazy[k])%mod;
	addlazy[rch(k)]=(addlazy[rch(k)]*mullazy[k]+addlazy[k])%mod;
	mullazy[lch(k)]=(mullazy[lch(k)]*mullazy[k])%mod;
	mullazy[rch(k)]=(mullazy[rch(k)]*mullazy[k])%mod;
	addlazy[k]=0;
	mullazy[k]=1;
}

void add(int k,int l,int r,ll num){
	if(lc(k)>=l&&rc(k)<=r){
		v(k)=(v(k)+num*tr[k].length)%mod;
		addlazy[k]+=num;
		return ;
	}
	pushdown(k);
	int mid=lc(k)+rc(k)>>1;
	if(l<=mid)add(lch(k),l,r,num);
	if(r>mid) add(rch(k),l,r,num);
	pushup(k);
}

void mul(int k,int l,int r,ll num){
	if(lc(k)>=l&&rc(k)<=r){
		v(k)=(v(k)*num)%mod;
		addlazy[k]=(addlazy[k]*num)%mod;
		mullazy[k]=(mullazy[k]*num)%mod;
		return ;
	}
	pushdown(k);
	int mid=lc(k)+rc(k)>>1;
	if(l<=mid)mul(lch(k),l,r,num);
	if(r>mid) mul(rch(k),l,r,num);
	pushup(k);
}

ll query(int k,int l,int r){
	if(lc(k)>=l&&rc(k)<=r)
		return v(k)%mod;
	pushdown(k);
	int mid=lc(k)+rc(k)>>1;
	ll ret=0;
	if(l<=mid)ret+=query(lch(k),l,r);
	if(r>mid) ret+=query(rch(k),l,r);
	return ret%mod;
}

void build(int k,int l,int r){
	lc(k)=l;rc(k)=r;
	mullazy[k]=1;
	tr[k].length=r-l+1;
	if(l==r){
		v(k)=val[l];
		return;
	}
	int mid=l+r>>1;
	build(lch(k),l,mid);
	build(rch(k),mid+1,r);
	pushup(k);
}

int main(){
	scanf("%d%d%lld",&n,&m,&mod);
	for(int i=1;i<=n;i++){
		scanf("%d",&val[i]);
	}
	build(1,1,n);
	for(int i=1;i<=m;i++){
		int opt,l,r;
		ll num;
		scanf("%d%d%d",&opt,&l,&r);
		if(opt==2){
			scanf("%lld",&num);
			add(1,l,r,num);
		}
		else if(opt==1){
			scanf("%lld",&num);
			mul(1,l,r,num);
		}
		else{
			printf("%lld\n",query(1,l,r)%mod);
		}
	}
	return 0;
}

点双联通分量

#include<cstdio>
#include<cctype>
#include<vector>
using namespace std;
struct edge
{
    int to,pre;
}edges[1000001];
int head[1000001],dfn[1000001],dfs_clock,tot;
int num;//BCC数量 
int stack[1000001],top;//栈 
vector<int>bcc[1000001];
int tarjan(int u,int fa){
    int lowu=dfn[u]=++dfs_clock;
    for(int i=head[u];i;i=edges[i].pre)
        if(!dfn[edges[i].to]){
            stack[++top]=edges[i].to;//搜索到的点入栈 
            int lowv=tarjan(edges[i].to,u);
            lowu=min(lowu,lowv);
            if(lowv>=dfn[u])//是割点或根 {
                num++;
                while(stack[top]!=edges[i].to)//将点出栈直到目标点 
                    bcc[num].push_back(stack[top--]);
                bcc[num].push_back(stack[top--]);//目标点出栈 
                bcc[num].push_back(u);//不要忘了将当前点存入bcc 
            }
        }
        else if(edges[i].to!=fa)
            lowu=min(lowu,dfn[edges[i].to]);
    return lowu;
}
void add(int x,int y)//邻接表存边 {
    edges[++tot].to=y;
    edges[tot].pre=head[x];
    head[x]=tot;
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    for(int i=1;i<=n;i++)//遍历n个点tarjan 
        if(!dfn[i]){
            stack[top=1]=i;
            tarjan(i,i);
        }
    for(int i=1;i<=num;i++){
        printf("BCC#%d: ",i);
        for(int j=0;j<bcc[i].size();j++)
            printf("%d ",bcc[i][j]);
        printf("\n");
    }
    return 0;
}

桥以及强连通分量

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
queue < int > q;
const int maxn = 100010;
int head[maxn];
struct node{
	int to;
	int next;
}edge[5*maxn];
int n,m;
int cnt=1;
int instack[maxn];
int co[maxn];
int num[maxn];
int dfn[maxn],low[maxn];
int visn=1;
int stack[maxn];
int top=0;
int sum=0;
int cd[maxn];
int used[maxn];
void add(int from,int to){
	edge[cnt].to=to;
	edge[cnt].next=head[from];
	head[from]=cnt++;
}

void work(){
	cin>>n>>m;
	memset(head,-1,sizeof(head));
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		add(x,y);
	}
	return ;
}

void tarjan(int u){
	instack[u]=1;
	dfn[u]=low[u]=visn++;
	stack[++top]=u;
	for(int i=head[u];i!=-1;i=edge[i].next){
		int v=edge[i].to;
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[v],low[u]);
		}
		else if(instack[v]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(dfn[u]==low[u]){
		sum++;
		int v;
		do{
			v=stack[top--];
			co[v]=sum;
			num[sum]++;
		}while(v!=u);
	}
}

int main(){
	work();
	for(int i=1;i<=n;i++){
		if(!dfn[i])
		tarjan(i);
	}
}

欧拉筛以及莫比乌斯函数

void work(){
	u[1]=1;vis[1]=1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prime[++tot]=i;
			u[i]=-1;
		}
		for(int j=1;j<=tot&&i*prime[j]<=n;j++){
			vis[prime[j]*i]=1;
			if(i%prime[j]==0)break;
			u[prime[j]*i]=-u[i];
			
		}
	}
}

treap

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int maxn = 100007;
typedef long long ll;
int sz[maxn],cov[maxn];
ll num[maxn],ran[maxn];
int ch[maxn][2],m,tot;
const int INF = 2147483647;
#define lch(x) ch[x][0]
#define rch(x) ch[x][1]
int root;int mod=20030625;
void pushup(int k){sz[k]=sz[lch(k)]+sz[rch(k)]+cov[k];}
int New(ll val){
	ran[++tot]=(rand()*rand())%mod;
	num[tot]=val;cov[tot]=sz[tot]=1;
	return tot;
}
void zig(int &k){// left
	int y=rch(k);rch(k)=lch(y);
	lch(y)=k;sz[y]=sz[k];
	pushup(k);k=y;
}
void zag(int &k){// right
	int y=lch(k);lch(k)=rch(y);
	rch(y)=k;sz[y]=sz[k];
	pushup(k);k=y;
}
void insert(int &k,ll val){
	if(!k){k=New(val);return;}
	if(num[k]==val){cov[k]++;pushup(k);return;}
	else if(num[k]<val){
		insert(rch(k),val);
		if(ran[rch(k)]<ran[k])zig(k);
	}else{
		insert(lch(k),val);
		if(ran[lch(k)]<ran[k])zag(k);
	}
	pushup(k);
}
void Del(int &k,ll val){
	if(!k)return;
	if(num[k]==val){
		if(cov[k]>1){cov[k]--;pushup(k);return;}
		if(!lch(k)||!rch(k))k=lch(k)+rch(k);
		else if(ran[lch(k)]<ran[rch(k)])zag(k),Del(k,val);
		else zig(k),Del(k,val);
	}
	else if(num[k]>val)Del(lch(k),val);
	else Del(rch(k),val);
	pushup(k);
}
ll QueryFro(ll val){
	int k=root;ll ret=0;
	while(k){
		if(!k)return 0;
		else if(val>num[k])ret=num[k],k=rch(k);
		else k=lch(k);
	}return ret;
}
ll QueryPas(ll val){
	int k=root;ll ret=0;
	while(k){
		if(!k)return 0;
		else if(val<num[k])ret=num[k],k=lch(k);
		else k=rch(k);
	}return ret;	
}
int QueryNumberRank(ll val){
	int k=root,ret=0;
	while(k){
		if(!k)return 0;
		if(num[k]==val)return (sz[lch(k)]+1+ret);
		else if(num[k]>val) k=lch(k);
		else ret+=sz[lch(k)]+cov[k],k=rch(k);
	}
}
ll QueryRankNumber(ll R){
	int k=root;
	while(k){
		if(!k)return 0;
		if(sz[lch(k)]<R&&R<=sz[lch(k)]+cov[k])return num[k];
		else if(R<=sz[lch(k)])k=lch(k);
		else R-=(sz[lch(k)]+cov[k]),k=rch(k);
	}
}
int n;
int main(){
	srand(20030625);
	insert(root,-INF);
	insert(root,INF);
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		int opt;ll val;scanf("%d%lld",&opt,&val);
		if(opt==1){insert(root,val);}
		else if(opt==2){Del(root,val);}
		else if(opt==3){printf("%lld\n",QueryNumberRank(val)-1);}
		else if(opt==4){printf("%lld\n",QueryRankNumber(val+1));}
		else if(opt==5){printf("%lld\n",QueryFro(val));}
		else {printf("%lld\n",QueryPas(val));}
	}
	return 0;
}

CDQ分治

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn = 1000007; 

int k,tr[maxn],n;
struct node{
	int a,b,c,num,ans;
}task[maxn];

bool cmp1(node a,node b){
	if(a.c==b.c)return (a.b==b.b)?a.a<b.a:a.b<b.b;
	return a.c<b.c;
}
bool cmp2(node a,node b){return a.b==b.b?a.a<b.a:a.b<b.b;}

int lowbit(int x){return x&-x;}
void add(int x,int num){
	for(;x<=k;x+=lowbit(x))tr[x]+=num;
}
int query(int x){
	int ret=0;
	for(;x;x-=lowbit(x))ret+=tr[x];
	return ret;
}
int ans[maxn];
void cdq(int l,int r){
	if(l==r)return;
	int mid=l+r>>1;
	cdq(l,mid),cdq(mid+1,r);
	sort(task+l,task+1+mid,cmp2);
	sort(task+mid+1,task+1+r,cmp2);
	int i=mid+1,j=l;
	for(;i<=r;i++){
		while(task[i].b>=task[j].b&&j<=mid)
			add(task[j].a,task[j].num),j++;
		task[i].ans+=query(task[i].a);
	}
	for(i=l;i<j;i++)
		add(task[i].a,-task[i].num);
}

int main(){
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++){
		scanf("%d%d%d",&task[i].a,&task[i].b,&task[i].c);
	}sort(task+1,task+1+n,cmp1);
	int nn=n,sum=0;n=0;
	
	for(int i=1;i<=nn;i++){
		sum++;
		if(task[i].a!=task[i+1].a || task[i].b!=task[i+1].b || task[i].c!=task[i+1].c){
			task[++n]=(node){task[i].a,task[i].b,task[i].c,sum,0},sum=0;
		}
	}
	cdq(1,n);
	for(int i=1;i<=n;i++){
		ans[task[i].ans+task[i].num-1]+=task[i].num;
	}
	for(int i=0;i<nn;i++)
	printf("%d\n",ans[i]);
	return 0;
}

最长公共子序列

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 100007;
int lowbit(int x){return x&-x;}
int tr[maxn],n,a[maxn],b[maxn],c[maxn],ans;
int query(int x){
    int ret=0;
    for(;x;x-=lowbit(x))ret=max(ret,tr[x]);
    return ret;
}

void add(int x,int num){
    for(;x<=n;x+=lowbit(x)){
        tr[x]=max(tr[x],num);
    }
}



int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        c[a[i]]=i;
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&b[i]);
        b[i]=c[b[i]];//cout<<b[i]<<" ";
    }//cout<<endl;
    for(int i=1;i<=n;i++){
        int len=query(b[i]-1)+1;
        //cout<<len<<" "<<b[i]<<endl;
        ans=max(ans,len);
        add(b[i],len);
    }
    cout<<ans;
}

EK费用流

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 50007;
const int INF = 2147483647;
struct node{
	int to,next,flow,w;
}edge[maxn*3];
int cnt,head[maxn];

void add(int from,int to,int flow,int w){
	edge[++cnt].to=to;
	edge[cnt].flow=flow;
	edge[cnt].w=w;
	edge[cnt].next=head[from];
	head[from]=cnt;
}

int n,m,d[maxn],g[maxn],vis[maxn],pre[maxn];
int last[maxn];
bool EK_spfa(int s,int t){
	for(int i=1;i<=n;i++)d[i]=g[i]=INF;
	queue<int>q;vis[s]=1;q.push(s);d[s]=0;
	memset(vis,0,sizeof(vis));
	pre[t]=-1;
	while(!q.empty()){
		int f1=q.front();q.pop();
		vis[f1]=0;
		for(int i=head[f1];i!=-1;i=edge[i].next){
			int to=edge[i].to;
			if(edge[i].flow&&edge[i].w+d[f1]<d[to]){
				d[to]=d[f1]+edge[i].w;
				g[to]=min(g[f1],edge[i].flow);
				pre[to]=f1;last[to]=i;
				if(!vis[to])vis[to]=1,q.push(to);
			}
		}
	}
	return pre[t]!=-1;
}
int ans=0,cost=0;
void MFMC(int s,int t){
	while(EK_spfa(s,t)){
		ans+=g[t];cost+=g[t]*d[t];
		int now=t;
		while(now!=s){
			edge[last[now]].flow-=g[t];
			edge[last[now]^1].flow+=g[t];
			now=pre[now];
		}
	}
}

int s,t;
int main(){cnt=-1;
	memset(head,-1,sizeof(head)); 
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1;i<=m;i++){
		int x,y,f,w;
		scanf("%d%d%d%d",&x,&y,&f,&w);
		add(x,y,f,w);
		add(y,x,0,-w);
	}
	MFMC(s,t);
	printf("%d %d",ans,cost);
}

FFT

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn = 3e6+7;
const double Pi = acos(-1);
struct cp
{
    double x,y;
    cp(double xx=0.0,double yy=0.0)
    {x=xx,y=yy;}
}a[maxn],b[maxn];
int len=1,bit,rev[maxn];
cp operator +(cp xxx,cp yyy){return cp(xxx.x+yyy.x,xxx.y+yyy.y);}
cp operator *(cp xxx,cp yyy){return cp(xxx.x*yyy.x-xxx.y*yyy.y,xxx.x*yyy.y+xxx.y*yyy.x);}
cp operator -(cp xxx,cp yyy){return cp(xxx.x-yyy.x,xxx.y-yyy.y);}
void FFT(cp a[],int type){
    for(int i=0;i<len;i++) if(i<rev[i])swap(a[i],a[rev[i]]);
    for(int h=1;h<len;h*=2){
        cp wn(cos(Pi/h),type*sin(Pi/h));
        for(int i=0;i<len;i+=(h*2)){
            cp w(1,0);
            for(int k=0;k<h;k++){
                cp u=a[i+k],t=w*a[k+h+i];
                a[i+k]=u+t;a[k+h+i]=u-t;w=w*wn;
            }
        }
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<=n;i++)scanf("%lf",&a[i].x);
    for(int i=0;i<=m;i++)scanf("%lf",&b[i].x);
    while(len<=(n+m))len<<=1,bit++;
    for(int i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    FFT(a,1);FFT(b,1);
    for(int i=0;i<=len;i++)a[i]=a[i]*b[i];
    FFT(a,-1);
    for(int i=0;i<=n+m;i++)printf("%d ",(int)(fabs(a[i].x)/len+0.5));
    return 0;
}

单源最短路,当然不是spfa

void dij(int v0){
    for(int i=1;i<=n;i++)dis[i]=INF;
	q.push(make_pair(0,v0));dis[v0]=0;
    while(!q.empty()){
        int f1=q.top().first,f2=q.top().second;q.pop();
        if(-dis[f2]!=f1)continue;
        for(int i=head[f2];i;i=edge[i].next){
            int to=edge[i].to,w=edge[i].w;
            if(dis[to]>w+dis[f2]){
                dis[to]=w+dis[f2];
                q.push(make_pair(-dis[to],to));
            }
        }
    }
}

动态开点主席树

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 2e5+7; 
int n,m,tot,num[maxn],a[maxn],_hash[maxn],rt[maxn];

#define lch(x) ch[x][0]
#define rch(x) ch[x][1]
int ch[maxn*60][2],sum[maxn*60];

void build(int &k,int l,int r){
	if(!k)k=++tot;int mid=l+r>>1;
	sum[k]=0;if(l==r)return;
	build(lch(k),l,mid);
	build(rch(k),mid+1,r);
}

void update(int &k,int fa,int l,int r,int val){
	if(!k)k=++tot;int mid=l+r>>1;
	sum[k]=sum[fa]+1;if(l==r)return;
	if(val<=mid)rch(k)=rch(fa),update(lch(k),lch(fa),l,mid,val);
	else lch(k)=lch(fa),update(rch(k),rch(fa),mid+1,r,val);
}

int query(int k1,int k2,int l,int r,int Rank){
	if(l==r)return l;
	int mid=l+r>>1,sam=sum[lch(k2)]-sum[lch(k1)];
	if(Rank<=sam) return query(lch(k1),lch(k2),l,mid,Rank);
	else return query(rch(k1),rch(k2),mid+1,r,Rank-sam);
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&num[i]),a[i]=num[i];
	sort(a+1,a+1+n);int len=unique(a+1,a+1+n)-a-1;
	//for(int i=1;i<=len;i++)cout<<a[i]<<" ";
	for(int i=1;i<=n;i++)num[i]=lower_bound(a+1,a+1+len,num[i])-a;
	//for(int i=1;i<=n;i++)cout<<num[i]<<" ";
	build(rt[0],1,len);
	for(int i=1;i<=n;i++)update(rt[i],rt[i-1],1,len,num[i]);
	for(int i=1;i<=m;i++){
		int x,y,z;scanf("%d%d%d",&x,&y,&z);
		printf("%d\n",a[query(rt[x-1],rt[y],1,len,z)]);
	}
}

快速幂

ll ksm(ll a,ll b){
	if(b==0)return 1;
	ll ret=ksm(a,b/2)%k;
	ret=(ret*ret)%k;
	if(b%2==1)ret=(ret*a)%k;
	return ret%k;
}

KMP

void prework(){
	int j=0;
	for(int i=2;i<=m;i++){
		while(j&&ch2[j+1]!=ch2[i])j=p[j];
		if(ch2[j+1]==ch2[i])j++;
		p[i]=j;
	}
}

void KMP(){
	int j=0,ans=0;
	for(int i=1;i<=n;i++){
		while(j&&ch2[j+1]!=ch1[i])j=p[j];
		if(ch2[j+1]==ch1[i])j++;
		if(j==m)j=p[j],printf("%d\n",i-m+1);
	}
	for(int i=1;i<=m;i++)cout<<p[i]<<" ";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值