模板

模板整理(持续整理中)

基础算法

二分

while(l<=r)
{
    int mid=(l+r)/2;
    if(check(mid)) l=mid;
    else r=mid-1;
}

快速排序

void qsort(int l,int r)//应用二分思想
{
    int mid=a[(l+r)/2];//中间数
    int i=l,j=r;
    do{
        while(a[i]<mid) i++;//查找左半部分比中间数大的数
        while(a[j]>mid) j--;//查找右半部分比中间数小的数
        if(i<=j)//如果有一组不满足排序条件(左小右大)的数
        {
            swap(a[i],a[j]);//交换
            i++;
            j--;
        }
    }while(i<=j);//这里注意要有=
    if(l<j) qsort(l,j);//递归搜索左半部分
    if(i<r) qsort(i,r);//递归搜索右半部分
}

归并排序(包含求逆序对)

void mergesort(int l,int r)
{
    if(l>=r) return ;
    int mid=(l+r)>>1;
    mergesort(l,mid),mergesort(mid+1,r);
    int head1=l,head2=mid+1;
    for(int i=l;i<=r;i++)
    {
        if(head2<=r &&(head1>mid||a[head2]<a[head1]))
            q[i]=a[head2++];
        else
            q[i]=a[head1++],cnt+=(head2-mid-1);
    }
    for(int i=1;i<=r;i++)
        a[i]=q[i];
    return ;
}

高精度(重载运算符)

#include<algorithm>

char s[2333];

struct gaojing
{
	int n,z[2333];

	gaojing()
	{
		n=1;
		memset(z,0,sizeof(z));
	}
	
	void init()
	{
		scanf("%s",s+1);
		int l=strlen(s+1);
		reverse(s+1,s+l+1);

		n = l;
		for (int a=1;a<=n;a++)
			z[a] = s[a]-'0';
	}

	void print()
	{
		for (int a=n;a>=1;a--)
			printf("%d",z[a]);
	}
};


gaojing operator+(const gaojing &a,const gaojing &b)
{
	gaojing c;
	c.n = max(a.n,b.n);
	for (int i=1;i<=c.n;i++)
		c.z[i] = a.z[i] + b.z[i];
	for (int i=1;i<=c.n;i++)
	{
		c.z[i+1] += c.z[i]/10;
		c.z[i] = c.z[i]%10;
	}
	if (c.z[c.n+1] != 0) c.n++;
	return c;
}


gaojing operator*(const gaojing &a,const gaojing &b)
{
	gaojing c;
	c.n = a.n + b.n;
	for (int i=1;i<=a.n;i++)
		for (int j=1;j<=b.n;j++)
			c.z[i+j-1] += a.z[i] * b.z[j];
	for (int i=1;i<=c.n;i++)
	{
		c.z[i+1] += c.z[i]/10;
		c.z[i] = c.z[i]%10;
	}
	while (c.n != 1 && c.z[c.n] == 0)
		c.n--;
	return c;
}


bool operator<(const gaojing &a,const gaojing &b)
{
	if (a.n!=b.n) return a.n<b.n;
	for (int i=a.n;i>=1;i--)
		if (a.z[i] != b.z[i]) return a.z[i]<b.z[i];
	return false;
}

bool operator<=(const gaojing &a,const gaojing &b)
{
	if (a.n!=b.n) return a.n<b.n;
	for (int i=a.n;i>=1;i--)
		if (a.z[i] != b.z[i]) return a.z[i]<b.z[i];
	return true;
}


gaojing a,b;
if (a<=b) printf("gg");
else printf("ggg");

gaojing z[2333];
sort(z+1,z+n+1);

dfs

void dfs(int x){
    v[x]=1;//记录点x被访问过,v是visit的缩写
    for(int i=head[x];i;i=next[i]){
        int y=ver[i];
        if(v[y]) continue;
        dfs(y);
    }
}

bfs

void bfs()
{
    memset(d,0,sizeof(d));
    queue<int> q;
    q.push(1);d[1]=1;
    while(q.size()>0){
        int x=q.front();
        q.pop;
        for(int i=head[x];i;next[i]){
            int y=ver[i];
            if(d[y]) continue;
            d[y]=d[x]+1;
            q.push(y);
        }
    }
}

快速幂

//位运算版本
#include <iostream>
using namespace std;
int power(int a,int b,int p)
{
	int ans=1%p;
	for( ;b;b>>=1)
	{
		if(b&1)
		ans=(long long)ans*a%p;
		a=(long long)a*a%p; 
	}
	return ans;
}
int main()
{
	
} 
//递归版本
#include <iostream>
#include <cstdio>
using namespace std;
long long t,b,p,k,s,result=1;
int pow(int a,int b,int p)
{
	if(b==0)
	return 1;
	if(b==1)
	return a%p;
	t=pow(a,b/2,p);
	if(b>=2&&b%2==0)
	return t*t%p;
	if(b>=2&&b%2==1)
	return t*t*a%p;
}
int main()
{

} 

三维偏序

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
const int maxn=200005;
struct node{
	int x,y,z,id;
}a[maxn];
int c[maxn*4],k,n,b[maxn],qyj[maxn],f[maxn];
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int y)
{
	for( ;x<=k;x+=lowbit(x))
	c[x]+=y;
}
int ask(int x)
{
	int res=0;
	for( ;x;x-=lowbit(x))
	res+=c[x];
	return res;
}
bool cmp1(const node &a,const node &b)
{
	if(a.x!=b.x)
	return a.x<b.x;
	if(a.y!=b.y)
	return a.y<b.y;
	return a.z<b.z;
}
bool cmp2(const node &a,const node &b)
{
	if(a.y!=b.y)
	return a.y<b.y;
	if(a.z!=b.z)
	return a.z<b.z;
	return a.x<b.x;
}
void cdq(int l,int r)
{
	if(l==r)
	return ;
	int mid=(l+r)>>1;
	int flag;
	cdq(l,mid),cdq(mid+1,r);
	sort(a+l,a+r+1,cmp2);
	for(int i=l;i<=r;i++)
	(a[i].x<=mid)?add(a[i].z,1),flag=i:b[a[i].id]+=ask(a[i].z);
	for(int i=l;i<=r;i++)
	if(a[i].x<=mid)
	add(a[i].z,-1);
}
int main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	cin>>a[i].x>>a[i].y>>a[i].z,a[i].id=i;
	sort(a+1,a+1+n,cmp1);
	for(int i=1;i<=n; )
	{
		int j=i+1;
		while(j<=n&&a[j].x==a[i].x&&a[j].y==a[i].y&&a[j].z==a[i].z)
		j++;
		while(i<j)
		qyj[a[i].id]=a[j-1].id,i++;
	}
	for(int i=1;i<=n;i++)
	a[i].x=i;
	cdq(1,n);
	for(int i=1;i<=n;i++)
	f[b[qyj[a[i].id]]]++;
	for(int i=0;i<n;i++)
	cout<<f[i]<<'\n';
	return 0;
}

数据结构

并查集

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=10005; 
int f[maxn];
int n,m;
void init()
{
	for(int i=1;i<=10000;i++)
	f[i]=i;
}
int get(int x)
{
	return f[x]=(x==f[x]? x:get(f[x]));
}
void merge(int x,int y)
{
	f[get(x)]=get(y);
}
int main()
{
	
}

单调栈

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <stack>
using namespace std;
const int maxn=3000005;
int n;
int a[maxn],f[maxn];
stack <int> s;
int main()
{
	std::ios::sync_with_stdio(false);
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=n;i>=1;i--)
	{
		while(s.size()&&a[s.top()]<=a[i])
		s.pop();
		f[i]=s.empty()? 0:s.top();
		s.push(i);  
	}
	for(int i=1;i<=n;i++)
	cout<<f[i]<<" ";
	cout<<'\n';
	return 0;
}

单调队列

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int n,k;
int a[1000005],q[1000005];
int main()
{
	cin>>n>>k;
	for(int i=0;i<n;i++)
	cin>>a[i];
	int hh=0,tt=-1;
	for(int i=0;i<n;i++)
	{
		if(hh<=tt&&q[hh]<i-k+1)
		hh++;
		while(hh<=tt&&a[q[tt]]>=a[i])
		tt--;
		q[++tt]=i;
		if(i>=k-1)
		cout<<a[q[hh]]<<" ";
	}
	cout<<endl;
	hh=0,tt=-1;
	for(int i=0;i<n;i++)
	{
		if(hh<=tt&&q[hh]<i-k+1)
		hh++;
		while(hh<=tt&&a[q[tt]]<=a[i])
		tt--;
		q[++tt]=i;
		if(i>=k-1)
		cout<<a[q[hh]]<<" ";
	}
	cout<<endl;
	return 0;
}

ST表

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath> 
using namespace std;


//快速读入 
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

 
int n,m;
int a[100005];
int lg[100005]={-1};
int f[100005][50];

int main()
{
    std::ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		lg[i]=lg[i/2]+1;
	}
	for(int i=1;i<=n;i++)
	f[i][0]=a[i];
	for(int i=1;i<=lg[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]);
	}
	while(m--)
	{
		int l,r;
		cin>>l>>r;
		int len=lg[r-l+1];
		cout<<max(f[l][len],f[r-(1<<len)+1][len])<<endl;
	}
	return 0;
}

字典树

struct Trie{
	long long val[maxn],ch[maxn][26],size;
	Trie()
	{
		size=1;
		memset(ch[0],0,sizeof(ch[0]));
		memset(val,0,sizeof(val)); 
	}
	long long index(char c)
	{
		return c-'a';
	}
	void insert(char s[])
	{
		long long u=0,len=strlen(s+1);
		for(int i=1;i<=len;i++)
		{
			long long c=index(s[i]);
			if(!ch[u][c])
			{
				memset(ch[size],0,sizeof(ch[size]));
				ch[u][c]=size++;
			}
			u=ch[u][c];
		}
	}
	long long search(char s[])
	{
		long long u=0,len=strlen(s+1);
		for(int i=1;i<=len;i++)
		{
			long long c=index(s[i]);
			if(!ch[u][c]) return 0;
			u=ch[u][c];
		}
		if(!val[u])
		{
			val[u]=1;
			return 1;
		}
		return 2;
	}
}tree;

树状数组

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int n,m;
int a[500005],c[500005];
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int y)
{
	for( ;x<=n;x+=lowbit(x)) c[x]+=y;
}
int ask(int x)
{
	int ans=0;
	for(;x;x-=lowbit(x)) ans+=c[x];
	return ans;
}
int main()
{
    
}

线段树

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
const int maxn=100010;
int a[maxn+5];
struct tree{
	int l,r;
	long long dat,lazy;
}t[maxn*4+5];
void pushup(int k)
{
	t[k].dat=t[k<<1].dat+t[k<<1|1].dat;
}
void build(int k,int l,int r)
{
	t[k].l=l,t[k].r=r;
	if(l==r)
	{
		t[k].dat=a[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	pushup(k);
}
void pushdown(int k)
{
	if(t[k].lazy)
	{
		t[k<<1].dat+=t[k].lazy*(t[k<<1].r-t[k<<1].l+1);
		t[k<<1|1].dat+=t[k].lazy*(t[k<<1|1].r-t[k<<1|1].l+1);
		t[k<<1].lazy+=t[k].lazy;
		t[k<<1|1].lazy+=t[k].lazy;
		t[k].lazy=0;
	}
}
void updata(int k,int l,int r,int v)
{
	if(l<=t[k].l&&r>=t[k].r)
	{
		t[k].dat+=(long long)v*(t[k].r-t[k].l+1);
		t[k].lazy+=v;
		return ;
	}
	pushdown(k);
	int mid=(t[k].l+t[k].r)>>1;
	if(l<=mid)
	updata(k<<1,l,r,v);
	if(r>mid)
	updata(k<<1|1,l,r,v);
	pushup(k);
}
long long query(int k,int l,int r)
{
	if(l<=t[k].l&&r>=t[k].r)
	return t[k].dat;
	pushdown(k);
	int mid=(t[k].l+t[k].r)>>1;
	long long ans=0;
	if(l<=mid)
	ans+=query(k<<1,l,r);
	if(r>mid)
	ans+=query(k<<1|1,l,r);
	return ans;
}
int main()
{
	std::ios::sync_with_stdio(false);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int o;
		cin>>o;
		if(o==1)
		{
			int x,y,k;
			cin>>x>>y>>k;
			updata(1,x,y,k);
			continue;
		}
		else
		{
			int x,y;
			cin>>x>>y;
			cout<<query(1,x,y)<<'\n';
		}
	}
	return 0;
}

扫描线

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
const int maxn=1e6+5;
int n;
long long x1,y1,x2,y2;
long long x[maxn*2];
struct scanline{
	long long l,r,h;
	int mark;
	bool operator < (const scanline &rhs) const
	{
		return h<rhs.h;
	}
}line[maxn*2];
struct tree{
	int l,r;
	int sum;
	long long len;
}t[maxn*4];
void pushup(int k)
{
	if(t[k].sum)
	t[k].len=x[t[k].r+1]-x[t[k].l];
	else
	t[k].len=t[k<<1].len+t[k<<1|1].len;
}
void build(int k,int l,int r)
{
	t[k].l=l,t[k].r=r;
	t[k].len=0;
	t[k].sum=0;
	if(l==r)
	return ;
	int mid=(l+r)>>1;
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
}
void edit_tree(int k,long long l,long long r,int c)
{
	if(x[t[k].r+1]<=l||r<=x[t[k].l])
	return ;
	if(l<=x[t[k].l]&&x[t[k].r+1]<=r)
	{
		t[k].sum+=c;
		pushup(k);
		return ;
	}
	edit_tree(k<<1,l,r,c);
	edit_tree(k<<1|1,l,r,c);
	pushup(k);
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>x1>>y1>>x2>>y2;
		x[2*i-1]=x1,x[2*i]=x2;
		line[2*i-1]=(scanline){x1,x2,y1,1};
		line[2*i]=(scanline){x1,x2,y2,-1};
	}
	n<<=1;
	sort(line+1,line+1+n);
	sort(x+1,x+1+n);
	//离散化 
	int tot=unique(x+1,x+1+n)-x-1;
	build(1,1,tot-1);
	long long ans=0;
	for(int i=1;i<n;i++)
	{
		edit_tree(1,line[i].l,line[i].r,line[i].mark);
		
		ans+=t[1].len*(line[i+1].h-line[i].h);
	}
	cout<<ans<<endl;
	return 0;
}

可持久化线段树求第k小的数(主席树)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#define int long long
using namespace std;
const int maxn=200005;
const int INF=1e9;
struct tree{
	int ls,rs;
	int sum;
}t[maxn*20];
int n,m;
int c,tot;
int a[maxn],b[maxn],root[maxn];
int build(int l,int r)//建树 
{
	int p=++tot;//新增一个节点 
	t[p].sum=0;
	if(l==r)
	return p;
	int mid=(l+r)>>1;
	t[p].ls=build(l,mid);
	t[p].rs=build(mid+1,r);
	return p; 
}
int insert(int now,int l,int r,int x,int delta)
{
	int p=++tot;//新开一个节点 
	t[p]=t[now];
	if(l==r)
	{
		t[p].sum+=delta;//在副本上进行加减,保留了历史版本 
		return p;
	}
	int mid=(l+r)>>1;
	if(x<=mid)
	t[p].ls=insert(t[now].ls,l,mid,x,delta);
	else
	t[p].rs=insert(t[now].rs,mid+1,r,x,delta);
	t[p].sum=t[t[p].ls].sum+t[t[p].rs].sum;
	return p;
}
int ask(int p,int q,int l,int r,int k)//表示在p,q两个节点上,值域为[l,r],求第k小的数 
{
	if(l==r)
	return l;//左端点等于右端点,找到了答案 
	int mid=(l+r)>>1;
	int lcnt=t[t[p].ls].sum-t[t[q].ls].sum;
	if(k<=lcnt)
	return ask(t[p].ls,t[q].ls,l,mid,k);
	else
	return ask(t[p].rs,t[q].rs,mid+1,r,k-lcnt);
}
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		b[++c]=a[i];
	}
	sort(b+1,b+c+1);//离散化 
	c=unique(b+1,b+c+1)-(b+1);
	root[0]=build(1,c);
	for(int i=1;i<=n;i++)
	{
		int x=lower_bound(b+1,b+c+1,a[i])-b;//离散化continuing
		root[i]=insert(root[i-1],1,c,x,1);
	}
	for(int i=1;i<=m;i++)
	{
		int l,r,k;
		cin>>l>>r>>k;
		int ans=ask(root[r],root[l-1],1,c,k);
		cout<<b[ans]<<'\n';
	}
	return 0;
}

图论

边表

struct edge
{
	int e,next;//next代表下一条边的边号是多少 、e表示终点 
}ed[maxm];

int en,first[maxn];//en代表边的数量 first从i出发的第一个边的编号 

void add_edge(int s,int e)
{
	en++;
	ed[en].next=first[s];
	first[s]=en;
	ed[en].e=e;
}

for(int p=first[1];p!=0;p=ed[p].next)
ed[p].e; 

dfs序

//dfs求dfs序
void dfs(int now,int f)
{
	q[l[now]]=now;//q表示dfs序列 
	int x=l[now]+1;
	size[now]=1;
	for(int i=first[now];i;i=ed[i].next )
	if(ed[i].e!=f)
	{
		l[e->e]=x;
		dfs(ed[i].e);
		x=r[ed[i].e]+1;
		dfs(ed[i].e);
		size[now]+=size[ed[i].e];
	}
	r[now]=l[now]+size[now]-1;
}
l[1]=1,r[1]=n;


//bfs求dfs序
int front=1,tail=1;
q[1]=1;
for( ;front<=tail;)
{
	int now=q[front++];
	for(int i=first[now];i;i=ed[i].next)
	if(!vis[ed[i].e])
	{
		q[++tail]=ed[i].e;
		vis[ed[i].e]=true;
	}
}
for(int i=n;i>=1;i--)
{
	int now=q[i];
	size[now]=1;
	for(int i=first[now];i;i=ed[i].next )
	if(size[ed[i].e])
	size[now]+=size[ed[i].e];
}
l[1]=1;r[1]=n;
for(int i=1;i<=n;i++)
{
	int now=q[i];
	int x=l[now]+1;
	for(int i=first[now];i;i=ed[i].next)
	if(size[ed[i].e]<size[now])
	{
		l[ed[i].e]=x;
		r[ed[i].e]=l[ed[i].e]+size[ed[i].e]
		x=r[ed[i].e]+1;
	}
}
for(int i=1;i<=n;i++)
q[l[i]]=i;

求树的深度

void dfs(int x){
    v[x]=1;
    for(int i=first[x];i;i=ed[i].next){
        int e=ver[i];
        if(v[y]) continue;
        d[y]=d[x]+1;
        dfs(y);
    }
}

树的重心

void dfs(int x){
    v[x]=1;size[i]=1;
    int max_part=0;
    for(int i=first[x];i;i=ed[i].next){
        int e=ed[i].e;
        if(v[y]) continue;
        dfs(y);
        size[x]+=size[y];
        max_part=max(max_part,size[y]);
    }
    max_part=max(max_part,n-size[x]);
    if(max_part<ans){
        ans=max_part;
        pos=x;
    }
}

Bellman-ford

for(int i=1;i<=m;i++)
{
	cin>>s[i]>>e[i]>>d[i];
}
memset(dist,0x3f,sizeof(dist));
dist[1]=0;
for(int i=1;i<n;i++)
for(int j=1;j<=m;j++)
dist[e[j]]=min(dist[e[j]],dist[s[j]]);

Dijkstra

//dijkstra 常用
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
const int maxn=100010,maxm=1000010;
struct edge{
	int e,next,val;
}ed[maxm];
int en,first[maxn]; 
int n,m,s;
int d[maxn];
bool v[maxn];
priority_queue <pair<int,int> > q;
void add_edge(int s,int e,int w)
{
	en++;
	ed[en].next=first[s];
	first[s]=en;
	ed[en].e=e;
	ed[en].val=w;
}
void dijkstra()
{
	for(int i=1;i<=n;i++)
	d[i]=2147483647;
	memset(v,0,sizeof(v));
	d[s]=0;
	q.push(make_pair(0,s));
	while(q.size())
	{
		int x=q.top().second;
		q.pop();
		if(v[x]) continue;
		v[x]=1;
		for(int i=first[x];i;i=ed[i].next)
		{
			int y=ed[i].e,z=ed[i].val;
			if(d[y]>d[x]+z)
			{
				d[y]=d[x]+z;
				q.push(make_pair(-d[y],y));  
			}
		}
	}
}
int main()
{
	cin>>n>>m>>s;
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		add_edge(x,y,z);
	}
	dijkstra();
	for(int i=1;i<=n;i++)
	cout<<d[i]<<" ";
	cout<<endl;
	return 0; 
}

SPFA

//spfa 慎用
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#define re register
#define ll long long
using namespace std;
const int maxn=100010,maxm=1000010;
struct edge{
	int e,next,val;
}ed[maxm];
int en,first[maxn],d[maxn];
void add_edge(int s,int e,int w)
{
	en++;
	ed[en].next=first[s];
	first[s]=en;
	ed[en].e=e;
	ed[en].val=w;
}
bool v[maxn];
int n,m,s;
queue <int> q;
void spfa()
{
	for(re int i=1;i<=n;i++)
		d[i]=2147483647;
	memset(v,0,sizeof(v));
	d[s]=0,v[s]=1;
	q.push(s);
	while(q.size())
	{
		int x=q.front();
		q.pop();
		for(re int i=first[x];i;i=ed[i].next)
		{
			int y=ed[i].e,z=ed[i].val;
			if(d[y]>d[x]+z)
			{
				d[y]=d[x]+z;
				if(!v[y]) q.push(y);
			}
		}
	}
}
int main()
{
	cin>>n>>m>>s;
	for(re int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		add_edge(x,y,z); 
	}
	spfa();
	for(re int i=1;i<=n;i++)
	printf("%d ",d[i]);
	return 0;
}

SPFA判负环

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
using namespace std;
const int maxn=30005;
int n,m;
struct edge{
	int e,next,val;
}ed[maxn*2];
int en,first[maxn];
void add_edge(int s,int e,int val)
{
	en++;
	ed[en].next=first[s];
	first[s]=en;
	ed[en].e=e;
	ed[en].val=val;
}
void reset()
{
	for(int i=0;i<maxn*2;i++)
	ed[i].next=ed[i].e=ed[i].val=0;
	for(int i=0;i<maxn;i++)
	first[i]=0;
}
int d[maxn],cnt[maxn];
bool vis[maxn];
queue <int> q;
bool spfa()
{
	memset(d,0x3f,sizeof(d));
	memset(vis,false,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	d[1]=0,vis[1]=true;
	q.push(1);
	while(q.size())
	{
		int x=q.front();
		q.pop();
		vis[x]=false;
		for(int i=first[x];i;i=ed[i].next)
		{
			int e=ed[i].e,val=ed[i].val;
			if(d[e]>d[x]+val)
			{
				d[e]=d[x]+val;
				cnt[e]=cnt[x]+1;
				if(cnt[e]>=n) return true;
				if(!vis[e])
				{
					q.push(e);
					vis[e]=true; 
				 }
			}
		}
	}
	return false;
}
int T; 
int main()
{
	cin>>T;
	while(T--)
	{
		cin>>n>>m;
		reset();
		for(int i=1;i<=m;i++)
		{
			int x,y,z;
			cin>>x>>y>>z;
			add_edge(x,y,z);
			if(z>=0)
			add_edge(y,x,z);
		}
		if(spfa())
		cout<<"YES"<<'\n';
		else 
		cout<<"NO"<<'\n'; 
	}
	return 0;
}

差分约束问题

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue>
#define int long long 
using namespace std;
const int maxn=50005;
struct edge{
	int e,next,val;
}ed[maxn*2];
int en,first[maxn];
void add_edge(int s,int e,int val)
{
	en++;
	ed[en].next=first[s];
	first[s]=en;
	ed[en].e=e;
	ed[en].val=val;
}
int n,m;
int d[maxn],num[maxn];
bool vis[maxn];
queue <int> q;
bool spfa(int x)
{
	d[x]=0;
	q.push(x); 
	vis[x]=true;
	num[x]++;
	while(q.size())
	{
		int x=q.front();
		q.pop();
		vis[x]=false;
		for(int i=first[x];i;i=ed[i].next)
		{
			int e=ed[i].e,val=ed[i].val;
			if(d[e]>d[x]+val)
			{
				d[e]=d[x]+val;
				if(!vis[e])
				{
					q.push(e);
					vis[e]=true;
					num[e]++;
					if(num[e]==n+1)
					return false;
				}
			}
		}
	}
	return true; 
}
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	d[i]=2147483647;
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		add_edge(y,x,z);
	}
	for(int i=1;i<=n;i++)
	add_edge(n+1,i,0);
	if(!spfa(n+1))
	{
		cout<<"NO"<<'\n';
		goto end;
	}
	for(int i=1;i<=n;i++)
	cout<<d[i]<<" ";
	end: ;
	return 0;
}

Floyd

for(int k=1;k<=n;k++)
    for(int i=1;i<=n;i++)
        for(iny j=1;j<=n;j++)
            a[i][j]=min(a[i][j],a[i][k]+a[k][j]);

最小生成树Kruskal

//Kruskal
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#define re register
#define ll long long
using namespace std;
struct rec{int x,y,z;}edge[500010];
int fa[100010],n,m,ans;
bool operator <(rec a,rec b)
{
	return a.z<b.z;
}
int get(int x)
{
	return fa[x]=(x==fa[x])? x:get(fa[x]);
}
int main()
{
	cin>>n>>m;
	for(re int i=1;i<=m;i++)
		cin>>edge[i].x>>edge[i].y>>edge[i].z;
	sort(edge+1,edge+m+1);
	for(re int i=1;i<=n;i++) fa[i]=i;
	for(re int i=1;i<=m;i++)
	{
		int x=get(edge[i].x);
		int y=get(edge[i].y);
		if(x==y) continue;
		fa[x]=y;
		ans+=edge[i].z;
	}
	cout<<ans<<endl;
	return 0;
}

最小生成树Prim

//Prim 
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#define re register
#define ll long long
using namespace std;
int a[5005][5005],n,m,ans,d[5005];
bool v[5005];
void prim()
{
	memset(d,0x3f,sizeof(d));
	memset(v,0,sizeof(v));
	d[1]=0;
	for(re int i=1;i<=n;i++)
	{
		int x=0;
		for(re int j=1;j<=n;j++)
		if(!v[j]&&(x==0||d[x]>d[j])) x=j;
		v[x]=1;
		for(re int y=1;y<=n;y++)
		if(!v[y]) d[y]=min(d[y],a[x][y]);
	}
}
int main()
{
	cin>>n>>m;
	memset(a,0x3f,sizeof(a));
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		a[y][x]=a[x][y]=min(a[x][y],z);
	}
	prim();
	for(int i=2;i<=n;i++) ans+=d[i];
	cout<<ans<<endl;
	return 0;
}

最近公共祖先Lca(倍增)

注意要设置
fa[s][0]=0,dep[s]=1

void dfs1(int x)
{
	for(int i=1;(1<<i)<=dep[x];i++)
	fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int i=first[x];i;i=ed[i].next)
	{
		int e=ed[i].e;
		if(e==fa[x][0]) continue;
		fa[e][0]=x;
		dep[e]=dep[x]+1;
		dfs1(e);
	}
}
int get_lca(int x,int y)
{
	if(x==y) return x;
	if(dep[x]<dep[y]) swap(x,y);
	int t=log(dep[x]-dep[y])/log(2);
	for(int i=t;i>=0;i--)
	{
		if(dep[fa[x][i]]>=dep[y])
		x=fa[x][i];
		if(x==y)
		return x;
	}
	t=log(dep[x])/log(2);
	for(int i=t;i>=0;i--)
	{
		if(fa[x][i]!=fa[y][i])
		x=fa[x][i],y=fa[y][i];
	}
	return fa[x][0];
}

Tarjan求强连通分量

void dfs(int now)
{
	t++;//找到了一个新的点 
	dfn[now]=low[now]=t;//dfn代表dfs的顺序,low表示从i点出发,可以向下走或者走回边
	//能走到的所有点中dfn值最小是多少 ,赋值为t是因为它最先走到它自己 
	s[++size]=now;//储存当前点的祖先或在环里面且为确定为连通分量的点 
	instack[now]=true;
	for(int i=first[now];i;i=ed[i].next)
	{
		int e=ed[i].e;
		if(!dfn[e])
		{
			dfs(e);
			low[now]=min(low[now],low[e]);//e能走到的所有点now也可以走到 
		}
		else
		{
			if(instack[e])
			low[now]=min(low[now],dfn[e]);
			//还没有从栈里面弹出来,所以他的祖先在栈里面,这是一条回边 
		}
	 }
	 if(dfn[now]==low[now])//如果自己dfn值和low值一样,要取出这个点了 
	 {
	 	cnt++;
	 	belong[now]=cnt;//now 这个节点属于新的连通分量 
	 	while(s[size]!=now)//在栈now后面的都属于和now的同一个强连通分量 
	 	{
	 		belong[s[size]]=cnt;
	 		instack[s[size]]=false;
	 		size--;
		 }
		 size--;
		 instack[now]=false;
	 }
}
//zhx的缩点
for(int i=1;i<=n;i++)
if(!dfn[i]) dfs(i);

for(int i=1;i<=n;i++)
	for(int j=first[i];j;j=ed[j].next)
	if(belong[i]!=belong[ed[j].e])
	add_edge2(belong[i],belong[ed[j].e]);

拓扑排序

int size=0;
for(int i=1;i<=n;i++)
if(!in[i])
{
	size++;
	q[size]=i;
}

for(int i=1;i<=n;i++)
{
	int now=q[i];
	for(int j=first[now];j;j=ed[j].next)
	{
		int e=ed[j].e;
		in[e]--;
		if(!in[e])
		{
			size++;
			q[size]=e;
		} 
	}
}

缩点

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
const int maxn=100005;
int t,dfn[maxn],low[maxn];
int tot,belong[maxn],sum[maxn],f[maxn];
int s[maxn],top;
int n,m,val[maxn],x[maxn*2],y[maxn*2],ans;
bool instack[maxn];
struct edge{
	int e,next;
}ed[maxn*2];
int en,first[maxn];
void add_edge(int s,int e)
{
	en++;
	ed[en].next=first[s];
	first[s]=en;
	ed[en].e=e;
}
void tarjan(int x)
{
	s[++top]=x;
	instack[x]=true;
	t++;
	dfn[x]=low[x]=t;
	for(int i=first[x];i;i=ed[i].next)
	{
		int e=ed[i].e;
		if(!dfn[e])
		{
			tarjan(e);
			low[x]=min(low[x],low[e]);
		}
		else if(instack[e])
		{
			low[x]=min(low[x],dfn[e]);
		}
	}
	if(dfn[x]==low[x])
	{
		tot++;
		while(s[top+1]!=x)
		{
			belong[s[top]]=tot;
			sum[tot]+=val[s[top]];
			instack[s[top--]]=false;
		}
	}
}
void search(int x)
{
	if(f[x])
	return ;
	f[x]=sum[x];
	int maxsum=0;
	for(int i=first[x];i;i=ed[i].next)
	{
		int e=ed[i].e;
		if(!f[e])
		search(e);
		maxsum=max(maxsum,f[e]);
	}
	f[x]+=maxsum;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>val[i];
	for(int i=1;i<=m;i++)
	{
		cin>>x[i]>>y[i];
		add_edge(x[i],y[i]);
	}
	for(int i=1;i<=n;i++)
	if(!dfn[i])
	tarjan(i);
	memset(ed,0,sizeof(ed));
	memset(first,0,sizeof(first));
	en=0;
	for(int i=1;i<=m;i++)
	{
		if(belong[x[i]]!=belong[y[i]])
		add_edge(belong[x[i]],belong[y[i]]);
	}
	for(int i=1;i<=tot;i++)
	{
		if(!f[i])
		{
			search(i);
			ans=max(ans,f[i]);
		}
	}
	cout<<ans<<endl;
	return 0;
}

求边双连通分量

dfn[2333],low[2333];//和tarjan的相同 
void dfs(int now,int from)//from指的是当前从那一条边走过来的 
{
	t++;
	dfn[now]=low[now]=t;
	vis[now]=true;
	for(int i=first[now];i;i=ed[i].next)//一条无向边会被拆为两条有向边形成死循环 
	if((i^1)!=from)
	{
		int e=ed[i].e;
		if(!dfb[e])
		{
			dfs(e,i);
			low[now]=min(low[now],low[e]);
		}
		else
		{
			if(vis[e])
			low[now]=min(low[now],dfn[e]);
		}
	}
	vis[e]=false;
}

匈牙利算法求最大二分图匹配

int n,m;//左边有n个人,右边有m个人 

bool dfs(int i)//让左边第i个人尝试匹配,看是否成功 
{
	for(int j=1;j<=m;j++)
	if(match[i][j]&&!use[j])
	{
		use[j]=true;
		if(!result[j]||dfs(result[j]))//result[i]表示右边的i和左边的某个数匹配 
		{
			result[j]=i;
			return true;
		}
	}
	return false;
}
int xiongyali()
{
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		memset(use,false,sizeof(use));
		if(dfs(i)) ans++;//匹配成功就把答案加一 
	}
	return ans;
} 

Dinic求网络最大流

Dinic
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <queue> 
using namespace std;
const long long inf=2005091500;
int n,m,s,t,u,v;
long long w,ans,d[520010];
int en=1,now[520010],first[520010]; 
struct edge {
	int e,next;
	long long val;
} ed[520010];

inline void add_edge(int u,int v,long long w) 
{
	ed[++en].e=v;
	ed[en].val=w;
	ed[en].next=first[u];
	first[u]=en;
	
	ed[++en].e=u;
	ed[en].val=0;
	ed[en].next=first[v];
	first[v]=en;
}

inline int bfs() {
	for(register int i=1;i<=n;i++) 
	d[i]=inf;
	queue<int> q;
	q.push(s);
	d[s]=0;
	now[s]=first[s];
	while(!q.empty()) 
	{
		int x=q.front();
		q.pop();
		for(register int i=first[x];i;i=ed[i].next)
		{
			int e=ed[i].e;
			if(ed[i].val>0&&d[e]==inf)
			{
				q.push(e);
				now[e]=first[e];
				d[e]=d[x]+1;
				if(e==t) return 1;
			}
		}
	}
	return 0;
}

inline int dfs(int x,long long sum) 
{
	if(x==t) return sum;
	long long k,res=0; 
	for(register int i=now[x];i&&sum;i=ed[i].next) 
	{
		now[x]=i;  
		int e=ed[i].e;
		if(ed[i].val>0&&(d[e]==d[x]+1)) 
		{
			k=dfs(e,min(sum,ed[i].val));
			if(k==0) d[e]=inf;  
			ed[i].val-=k;
			ed[i^1].val+=k;
			res+=k;
			sum-=k;  
		}
	}
	return res;
}

int main() 
{
	cin>>n>>m>>s>>t;
	for(register int i=1;i<=m;i++) 
	{
		cin>>u>>v>>w;
		add_edge(u,v,w);
	}
	while(bfs()) 
		ans+=dfs(s,inf); 
	cout<<ans<<endl;
	return 0;
}

求乘法逆元

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
long long n,p;
long long inv[3000010];
int main()
{
	cin>>n>>p;
	inv[1]=1;
	printf("1\n");
	for(int i=2;i<=n;i++)
	{
		inv[i]=(long long)(p-p/i)*inv[p%i]%p;
		printf("%lld\n",inv[i]);
	}
	return 0;
}

动态规划

最长公共子序列

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int n;
int a[100005],b[100005],map[100005],f[100005];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		map[a[i]]=i;
	}
	for(int i=1;i<=n;i++)
	{
		cin>>b[i];
		f[i]=0x3f;
	}
	int len=0;
	f[0]=0;
	for(int i=1;i<=n;i++)
	{
		int l=0,r=len,mid;
		if(map[b[i]]>f[len]) 
		f[++len]=map[b[i]];
		else
		{
			while(l<r)
			{
				mid=(l+r)>>1;
				if(f[mid]>map[b[i]])
				r=mid;
				else
				l=mid+1;
			}
			f[l]=min(map[b[i]],f[l]);
		}
	}
	cout<<len<<endl;
	return 0;
}

字符串

数学

欧拉素数筛

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn=10000005;
int v[maxn],p[maxn];//v代表v是不是质数,是的话为1,p为质数
void primes(int n)
{
	for(int i=2;i<=n;i++)
	{
   	 	if(!vis[i])
    	    p[++t]=i;
  		for(int j=1;j<=t&&i*p[j]<=n;j++)
   	    {
       	    vis[i*p[j]]=1;
            if(i%p[j]==0)
                break;
        }
    }
} 
int main()
{
	
}

筛欧拉函数

void init()
{
	for(int i=2;i<=maxn;i++)
	{
		if(!vis[i])
		pri[++tot]=i,phi[i]=i-1;
		for(int j=1;j<=tot&&pri[j]*i<=maxn;j++)
		{
			vis[pri[j]*i]=1;
			if(i%pri[j])
			phi[i*pri[j]]=phi[i]*phi[pri[j]];
			else
			{
				phi[i*pri[j]]=phi[i]*pri[j];
			}
		}
	}
}

欧几里得算法

int gcd(int a,int b)
{
    return b? gcd(b,a%b):a;
}

拓展欧几里得

long long exgcd(long long a,long long b,long long &x,long long &y)
{
	if(b==0)
	{
		x=1,y=233;
		return a;
	}
	long long xp,yp;
	long long g=exgcd(b,a%b,xp,yp);
	x=yp;
	y=xp-a/b*yp;
	return g;
}

中国剩余定理

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int gcd(int a,int b)
{
	return b? gcd(b,a%b):a;
}
int lcm(int a,int b)
{
	return a*b/gcd(a,b);
}
long long n,ans,tot=1;
int a[15],b[15];
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i]>>b[i];
	ans=b[1];
	for(int i=1;i<n;i++)
	{
		int l=lcm(tot,a[i]);
		tot=lcm(tot,a[i]);
		while(ans%a[i+1]!=b[i+1])
		{
			ans+=tot;
		}
	}
	cout<<ans<<endl;
	return 0;
}

高斯消元法

double z[110][110];
int n;
double gauss()
{
	double x=1;
	for (int a=1;a<=n;a++)
	{
		for (int b=a;b<=n;b++)
			if (fabs(z[b][a]) > 1e-8)
			{
				if (b==a) break;
				x=-x;
				for (int c=1;c<=n;c++)
					swap(z[b][c],z[a][c]);
				break;
			}
		if (fabs(z[a][a]) <= 1e-8) return 0.0;
		for (int b=a+1;b<=n;b++)
		{
			double k = z[b][a] / z[a][a];
			for (int c=1;c<=n;c++)
				z[b][c] = z[b][c] - z[a][c] * k;
		}
	}
	for (int a=1;a<=n;a++)
		x=x*z[a][a];
	return x;
}

矩阵快速幂

//本题为求斐波那契数
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
struct matrix{
	int n,m,z[233][233];
	matrix()
	{
		n=m=0;
		memset(z,0,sizeof(z));
	}
};
matrix operator*(const matrix &a,const matrix &b)
{
	matrix c;
	c.n=a.n;
	c.m=b.m;
	for(int i=1;i<=c.n;i++)
	for(int j=1;j<=c.m;j++)
	for(int k=1;k<=a.m;k++)
	c.z[i][j]=c.z[i][j]+a.z[i][k]*b.z[k][j];
	return c;
}
matrix base;
matrix ksm(int y)
{
	matrix ans;
	ans.z[1][1]=1,ans.z[1][2]=0;
	while(y)
	{
		if(y&1) ans=ans*base;
		base=base*base;
		y>>=1;
	}
	return ans;
}
int main()
{
	int n;
	cin>>n;
	base.z[1][1]=base.z[1][2]=base.z[2][1]=1;
	
	matrix sol=ksm(n-1);
	cout<<sol.z[1][1]<<endl;
	return 0;
}

nim游戏

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int t,n;
int main()
{
	cin>>t;
	while(t--)
	{
		int ans=0;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			int a;
			cin>>a;
			ans=ans^a;
		}
		if(ans)
		cout<<"Yes"<<endl;
		else
		cout<<"No"<<endl;
	}
	return 0;
}

Lucas定理

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
long long a[100005];
int T;
long long ksm(long long a,long long b,long long p)
{
	long long ans=1%p;
	for( ;b;b>>=1)
	{
		if(b&1)
		ans=(long long)ans*a%p;
		a=(long long)a*a%p; 
	}
	return ans;
}
long long C(long long n,long long m,long long p)
{
	if(m>n)
	return 0;
	return ((a[n]*ksm(a[m],p-2,p))%p*ksm(a[n-m],p-2,p)%p);
}
long long lucas(long long n,long long m,long long p)
{
	if(!m)
	return 1;
	return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
int main()
{
	cin>>T;
	a[0]=1;
	while(T--)
	{
		int n,m,p;
		cin>>n>>m>>p;
		a[0]=1;
		for(int i=1;i<=p;i++)
		a[i]=(a[i-1]*i)%p;
		cout<<lucas(n+m,m,p)<<endl;
	}
	return 0;
}

计算几何

posted @ 2020-10-24 20:10  wweiyi  阅读(133)  评论(0编辑  收藏  举报
js脚本