由于作者代码太丑少部分为原题解
最短路模块
spfa
#include<bits/stdc++.h>
const long long inf=2147483647;
const int maxn=10005;
const int maxm=500005;
using namespace std;
int n,m,s,num_edge=0;
int dis[maxn],vis[maxn],head[maxm];
struct Edge
{
int next,to,dis;
}edge[maxm]; //结构体表示静态邻接表
void addedge(int from,int to,int dis) //邻接表建图
{ //以下是数据结构书上的标准代码,不懂翻书看解释
edge[++num_edge].next=head[from]; //链式存储下一条出边
edge[num_edge].to=to; //当前节点编号
edge[num_edge].dis=dis; //本条边的距离
head[from]=num_edge; //记录下一次的出边情况
}
void spfa()
{
queue<int> q; //spfa用队列,这里用了STL的标准队列
for(int i=1; i<=n; i++)
{
dis[i]=inf; //带权图初始化
vis[i]=0; //记录点i是否在队列中,同dijkstra算法中的visited数组
}
q.push(s); dis[s]=0; vis[s]=1; //第一个顶点入队,进行标记
while(!q.empty())
{
int u=q.front(); //取出队首
q.pop(); vis[u]=0; //出队标记
for(int i=head[u]; i; i=edge[i].next) //邻接表遍历,不多解释了(也可用vector代替)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].dis) //如果有最短路就更改
{
dis[v]=dis[u]+edge[i].dis;
if(vis[v]==0) //未入队则入队
{
vis[v]=1; //标记入队
q.push(v);
}
}
}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=1; i<=m; i++)
{
int f,g,w;
cin>>f>>g>>w;
addedge(f,g,w); //建图,有向图连一次边就可以了
}
spfa(); //开始跑spfa
for(int i=1; i<=n; i++)
if(s==i) cout<<0<<" "; //如果是回到自己,直接输出0
else cout<<dis[i]<<" "; //否则打印最短距离
return 0;
}
Djisktra
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int m,n,s,ji,head[200005],dis[200005];
bool bo[200005];
struct node{
int w,next,yuan;
}ed[200005];
void add(int p,int q,int quan)
{
ed[++ji].w=quan;
ed[ji].yuan=q;
ed[ji].next=head[p];
head[p]=ji;
}
priority_queue < pair < int , int > > dui;//注意怎么写
int main(){
cin>>n>>m>>s;
for(int i=1;i<=m;i++){
int cm,cn,cs;
scanf("%d%d%d",&cm,&cn,&cs);
add(cm,cn,cs);
}
for(int i=1;i<=n;i++)dis[i]=0x7fffffff;//注意是只有初始化
dis[s]=0;
dui.push(make_pair(0,s));//注意make_pair怎么写,内容是什么
while(!dui.empty()){//注意有括号
int x=dui.top().second;//括号
dui.pop();
if(bo[x])continue;//记得判断重复
bo[x]=1;
for(int j=head[x];j;j=ed[j].next){
int y=ed[j].yuan,l=dis[x]+ed[j].w;
if(dis[y]>l){
dis[y]=l;
dui.push(make_pair(-dis[y],y));//是-dis[y]
}
}
}
for(int i=1;i<=n;i++)printf("%d ",dis[i]);
return 0;
}
spfa负环
#include<bits/stdc++.h>
#define IL inline
#define RI register int
#define N 100086
#define rk for(RI i=1;i<=m;i++)
using namespace std;
IL void read(int &x){cin>>x;}
int n,m,T;
struct node{
int next,yuan,w;
}ed[N];
bool bo[N];
int head[N],ji,dis[N],ans[N];
IL void add(int x,int y,int z){
ed[++ji].next=head[x];
ed[ji].yuan=y;
ed[ji].w=z;
head[x]=ji;
}
IL bool spfa(int now){
rk dis[i]=2147483647;
queue<int>dui;
dui.push(now);
bo[now]=1;
dis[now]=0;
while(!dui.empty()){
int x=dui.front();
dui.pop();
for(int i=head[x];i;i=ed[i].next){
int y=ed[i].yuan,l=dis[x]+ed[i].w;
if(dis[y]>l){
dis[y]=l;
ans[y]++;
dui.push(y);//不用判断是否在队列里面
bo[y]=1;
if(ans[y]>=n)return 1;
}
}
}
return 0;
}
int main(){
read(T);
while(T--)
{
read(n),read(m);
for(RI i=1,cm,cn,cw;i<=m;i++){
read(cm),read(cn),read(cw);
if(cw<0)add(cm,cn,cw);
else add(cm,cn,cw),add(cn,cm,cw);
}
if(!spfa(1))cout<<"N0"<<endl;
else cout<<"YE5"<<endl;
memset(head,0,sizeof(head));
memset(bo,0,sizeof(bo));
memset(ed,0,sizeof(ed));
memset(ans,0,sizeof(ans));
memset(head,0,sizeof(head));
ji=0;
}
}
最小生成树
#include<bits/stdc++.h>
using namespace std;
struct tree{
int yuan,next,w;
}ed[200005];
int m,ji,n,head[200005],ans,fa[200005];
bool cmp(tree a,tree b){
return a.w<b.w;//是<
}
int find(int k){
while(k!=fa[k])k=fa[k]=fa[fa[k]];
return k;
}
void kruskal(){
sort(ed+1,ed+n+1,cmp);
for(int i=1;i<=n;i++){
int x=find(ed[i].next),y=find(ed[i].yuan);
if(x==y)continue;
if(x>y){
fa[y]=x;
}
else
fa[x]=y;
ans+=ed[i].w;
if(++ji==m-1)return ;//n-1即可
}
}
int main(){
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>ed[i].next>>ed[i].yuan>>ed[i].w;//无需链式钱向星,否则yuan不对
}
for(int i=1;i<=m;i++)fa[i]=i;
ji=0;
kruskal();
cout<<ans;
}
LCA
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,s,tot=0,cnt=0;
int head[1000100],nxt[1000100],to[1000100];
int d[500100],f[30][1000100];
int read()
{
int x=0,flag=0;
char ch=getchar();
if(ch=='-') flag=1;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x*=10,x+=ch-'0',ch=getchar();
if(flag) return -x;
return x;
}
void addedge(int x,int y)
{
cnt++;
nxt[cnt]=head[x];
head[x]=cnt;
to[cnt]=y;
}
void dfs(int u,int dep)//处理出各个点的深度
{
d[u]=dep;
for(int i=head[u];i!=-1;i=nxt[i])
{
int v=to[i];
if(!d[v]) dfs(v,dep+1),f[0][v]=u;
}
}
int LCA(int x,int y)
{
int l=0;
while((1<<l)<=n) l++;
l--;//l表示的是最大的i为多少,当然,不用求l也可以,只要是一个够大的数像20即可
if(d[x]<d[y]) swap(x, y);//让x为深度较大的
for(int i=20;i>=0;i--)
if(d[y]<=d[x]-(1<<i)) x=f[i][x];//不断爬树,使深度相同
if(x==y) return x;
for(int i=20;i>=0;i--)
{
if(f[i][x]!=f[i][y])//不同就一起爬树
{
x=f[i][x];
y=f[i][y];
}
}
return f[0][x];
}
int main()
{
memset(head,-1,sizeof(head));
n=read(),m=read(),s=read();
for(int i=1;i<n;i++)
{
int x,y;
x=read(),y=read();
addedge(x,y);
addedge(y,x);
}
f[0][s]=s;
dfs(s,1);
for(int i=1;(1<<i)<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]=f[i-1][f[i-1][j]];//f[i][j] 表示 j的2^i 倍祖先,所以f[0][v]就是v的父亲节点u
for(int i=1;i<=m;i++)
{
int l,r;
l=read(),r=read();
printf("%d\n",LCA(l,r));
}
return 0;
}
数论模块
线性筛素数
#include<iostream>
using namespace std;
int m,n,prime[10000005],ji;
bool bo[10000005];
int main(){
cin>>m>>n;
for(int i=2;i<=m;i++){
if(bo[i]==0)//不能加括号!!!,每次都要更新!!!
prime[++ji]=i;
for(int j=1;i*prime[j]<=m;j++){//记得是prime[j]*i,i和j换个位置
bo[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
bo[1]=1,bo[0]=1;
for(int i=1;i<=n;i++){
int cn;
cin>>cn;
if(bo[cn])cout<<"No"<<endl;
else cout<<"Yes"<<endl;
}
}
快速幂
#include<bits/stdc++.h>
using namespace std;
long long m,n,mod;
long long quick(long long b,long long p){
if(p==0)return 1%mod;//为0才能返回,返回1还要mod
long long mid=p/2,bo=p%2;
long long t=quick(b,mid);
t=t*t%mod;
if(bo){
t=t*b%mod;
}
return t;
}
int main(){
cin>>m>>n>>mod;
cout<<m<<"^"<<n<<" mod "<<mod<<"="<<quick(m,n);
}
矩阵乘法
#include <bits/stdc++.h>
#define ll long long
#define m 1000000007
using namespace std;
inline ll gi(){
register char ch=getchar();register ll x=0;
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
ll n,k;
struct node {
ll mat[100][100];
}add,a,ans,mu,e,qk;
inline node mul(node x,node y){
node mem=qk;
for(register int i=1;i<=n;i++){
for(register int j=1;j<=n;j++){
for(register int h=1;h<=n;h++){
mem.mat[i][j]=(mem.mat[i][j]+x.mat[i][h]*y.mat[h][j])%m;
}
}
}
return mem;
}
inline void quick(ll k){
ans=e;
while(k){
if(k&1)ans=mul(ans,mu);
mu=mul(mu,mu);
k>>=1;
}
}
int main(){
cin>>n>>k;
for(register int i=1;i<=n;i++){
for(register int j=1;j<=n;j++){
mu.mat[i][j]=a.mat[i][j]=gi();
}
}
for(ll i=1;i<=n;i++){
e.mat[i][i]=1;
}
quick(k);
for(register int i=1;i<=n;i++){
for(register int j=1;j<=n;j++){
printf("%lld ",ans.mat[i][j]);
}
printf("\n");
}
return 0;
}
乘法逆元
#include<bits/stdc++.h>
using namespace std;
long long n,p,inv[3000001];
int main(){
cin>>n>>p;
inv[1]=1;
printf("1\n");
for(register long long i=2;i<=n;++i)
{
inv[i]=(p-p/i)*inv[p%i]%p;//a*x+b=p,a=[p/x],b=p%a;
printf("%lld\n",inv[i]);
}
return 0;
}
高斯消元
#include<bits/stdc++.h>
using namespace std;
double f[4005][4005],ans[400];
int n;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n+1;j++){
cin>>f[i][j];
}
}
for(int i=1;i<=n;i++){
int r=0;
for(int j=i;j<=n;j++)
if(fabs(f[r][i])<fabs(f[j][i]))//fabs返回实数的绝对值
r=j;
if(!r){
printf("No Solution");//找不到最大值即此列全为0
return 0;
}
swap(f[i],f[r]);//交换行骚操作~~~
double chu=f[i][i];//就是此列最大的那个关键元,那整列被放到第i行
for(int j=i;j<=n+1;j++)f[i][j]/=chu;//是i~n+1!,第1~i为0,本行除以这个关键元
for(int j=i+1;j<=n;j++){//枚举行数
chu=f[j][i];//当前行的关键元,要消去,且必须用中间变量(不然在后面的for里面值会被修改)
for(int k=i;k<=n+1;k++){//枚举列数,是i~n+1
f[j][k]-=f[i][k]*chu;//f[i][k]为这一列第一个,用关键元所在行对应列的来消此列其他值
// if(f[j][k]==-0)f[j][k]=0;
}
}
}
ans[n]=f[n][n+1];//因为是阶梯型矩阵,最后一行的第n+1个数就是xn的值
for(int i=n;i>=1;i--){//倒着枚举!
ans[i]=f[i][n+1];//本行结果初始化为第n+1个数
for(int j=i+1;j<=n;j++){
ans[i]-=ans[j]*f[i][j];//ans[j]中已经存放了xj的答案,乘本行第j个再减去就是xi的值
}
}
for(int i=1;i<=n;i++)
printf("%.2lf\n",ans[i]);
}
欧拉定理
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int n,mod,phi,k;
bool bo;
int quick(int a,int b){
int res=a,ans=1;
while(b){
if(b&1)ans=(long long)ans*res%mod;//要加ll...
res=(long long)res*res%mod;
b>>=1;
}
return ans%mod;
}
int main(){
cin>>n>>mod;
n%=mod;
int x=phi=mod;//等于mod...
for(int i=2;i*i<=x;i++){
if(x%i==0){
phi=phi/i*(i-1);
while(x%i==0)x/=i;
}
}if(x>1){phi=phi/x*(x-1);}
char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9'){
k=(k<<1)+(k<<3)+(ch^48);
ch=getchar();
if(k>=phi)bo=1,k%=phi;//>=&&%phi...
}
if(k>=phi)bo=1,k%=phi;
if(bo)k+=phi;
printf("%d",quick(n,k));
}
Pollard-Rho算法
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll ans=1;
inline ll quick(ll x,ll p,ll mod){
ll ans=1;
while(p){
if(p&1)ans=ans*x%mod;
x=x*x%mod; p>>=1;
}
return ans;
}
inline bool mr(ll x,ll p){
if(quick(x,p-1,p)!=1)return 0;
ll y=p-1,z;
while(!(y&1)){
y>>=1; z=quick(x,y,p);
if(z!=1&&z!=p-1)return 0;
return 1;
}return 1;
}
inline bool prime(ll p){ if(p<2)return 0;
if(p==2||p==3||p==5||p==11||p==101)return 1;
return mr(2,p)&&mr(3,p)&&mr(5,p)&&mr(11,p)&&mr(101,p);
}
inline ll Abs(ll x){return x<0?-x:x;}
inline ll gcd (ll a,ll b){
register ll t;
while (b){
t=a%b;
a=b;
b=t;
}
return a;
}
inline ll rho(ll p){
ll x,y,z,c,g; int i,j;
while(1){
x=y=rand()%p; c=rand()%p;
z=1; i=0; j=1;
while(++i){
x=((__int128)x*x+c)%p;
z=(__int128)z*Abs(y-x)%p;
if(x==y)break;
if(z==0){
g=gcd(Abs(y-x),p);
if(g>1)return g;
break;
}
if(!(i%127)||i==j){
g=gcd(z,p);
if(g>1)return g;
if(i==j)y=x,j<<=2;
}
}
}
}
inline void find(ll x){
if(x<=ans)return ;
if(prime(x)){ans=x;return ;}
ll p=rho(x);
while(x%p==0)x/=p;
find(p); find(x);
}
int main(){
int t;cin>>t;
srand(time(0));
while(t--){
ll n; ans=1;
cin>>n; find(n);
if(ans==n){puts("Prime");continue;}
printf("%lld\n",ans);
}
}
NIM博弈
#include<bits/stdc++.h>
using namespace std;
int t,n;
int main(){
cin>>t;
while(t--){
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
int ci;
cin>>ci;
ans^=ci;
}
if(ans)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
线性基
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll p[55],a,n,ans;
void merge(ll k){
for(int i=55;i>=0;i--){//>=0!!!!!!!!
if(!(k>>i))continue;
if(!p[i]){p[i]=k;break;}
k^=p[i];//消去最高位,后面的1不管,这也是为什么线性基不唯一——shuixirui
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a;
merge(a);
}
for(int i=55;i>=0;i--){
if((ans^p[i])>ans)ans^=p[i];
}
cout<<ans;
}
ST表
#include<bits/stdc++.h>
using namespace std;
int n,m,a[1000005],f[1000005][21];
int read(){
int x=0;char ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
int main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
f[i][0]=read();
}
for(int k=1;k<=20;k++){
for(int i=1;i<=n-(1<<k)+1;i++){
f[i][k]=max(f[i][k-1],f[i+(1<<(k-1))][k-1]);//将区间拆成两半[i,i+2^j-1]和[i+2^(j-1),j-1]
}
}
for(int i=1;i<=m;i++){
int le=read(),ri=read();
int t=log(ri-le+1)/log(2);//换底公式即log以2为ri-le+1的对数,找到最大的k
printf("%d\n",max(f[le][t],f[ri-(1<<t)+1][t]));// 左右两半区间查询
}
return 0;
}
并查集
#include<bits/stdc++.h>
using namespace std;
int m,n,fa[200005];
int find(int k){
while(k!=fa[k])k=fa[k]=fa[fa[k]];
return k;
}
int main(){
cin>>m>>n;
for(int i=1;i<=m;i++)fa[i]=i;
for(int k=1;k<=n;k++){
int cn,cm,ck;
cin>>cn>>cm>>ck;
int a=find(cm),b=find(ck);
if(cn==1){
if(a>b)fa[b]=a;
else fa[a]=b;
}
else if(a==b)puts("Y");
else puts("N");
}
}
最长公共子序列
#include<iostream>
#include<cstdio>
using namespace std;
int a[100005],b[100005],c[100005],f[100005],n;
int main(){
cin>>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]);
}
int len=0,l,r,mid;
for(int i=1;i<=n;i++){
l=0,r=len;
if(c[b[i]]>f[len]){//
f[++len]=c[b[i]];//是c[b[i]]!!!
}
else{
while(l!=r){
mid=(l+r)/2;
if(f[mid]>c[b[i]]){//是和c[b[i]]比较
r=mid;
}
else{
l=mid+1;//记得+1
}
}
f[l]=min(c[b[i]],f[l]);//记得取min
}
}
cout<<len;
}
数据结构模块
线段树1
#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
ll x=0;char ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return x;
}
long long n,m,a[100005];
struct node{
int le,ri,add;
ll sum;
}t[100005*4];
inline void build(ll p,ll l,ll r){
t[p].le=l,t[p].ri=r;
if(l==r){t[p].sum=a[l];return ;}
ll mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].sum+=t[p*2].sum+t[p*2+1].sum;
}
inline void spread(ll p){
if(t[p].add){
t[p*2].sum+=(ll)(t[p*2].ri-t[p*2].le+1)*t[p].add;
t[p*2+1].sum+=(ll)(t[p*2+1].ri-t[p*2+1].le+1)*t[p].add;
t[p*2].add+=t[p].add;
t[p*2+1].add+=t[p].add;
t[p].add=0;
}
}
inline void add(ll p,ll l,ll r,ll k){
if(t[p].le>=l&&t[p].ri<=r){
t[p].add+=k;
t[p].sum+=(ll)(t[p].ri-t[p].le+1)*k;
return ;
}
spread(p);//因为后面t[p].sum还有重新赋值操作所以要下方标记才能保证不变
register ll mid=(t[p].le+t[p].ri)>>1;
if(l<=mid)add(p*2,l,r,k);
if(r>mid)add(p*2+1,l,r,k);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
inline ll query(ll p,ll l,ll r){
if(t[p].le>=l&&t[p].ri<=r){
return t[p].sum;
}
spread(p);
register ll val=0,mid=(t[p].le+t[p].ri)>>1;
if(mid>=l)val+=query(p*2,l,r);
if(mid<r)val+=query(p*2+1,l,r);
return val;
}
int main(){
cin>>n>>m;
for(register int i=1;i<=n;i++){
a[i]=read();
}
build(1,1,n);
for(register int i=1;i<=m;i++){
register int typ=read();
if(typ==1){
register int cn=read(),cm=read(),ck=read();
add(1,cn,cm,ck);
}
else {
register int cn=read(),cm=read();
cout<<query(1,cn,cm)<<endl;//无论如何都要传入一个原始编号1
}
}
}
线段树2
#include <cstdio>
using namespace std;
typedef long long ll;
ll n,m,mod,num,typ,x,y,k,ans;
struct nod
{
ll l,r,w,add,mul;
}s[1000005];//四倍空间以上
ll build(ll x,ll L,ll R)
{
s[x]=nod{L,R,0,0,1};//构造函数,用来让代码更简洁
if(L==R)
{
scanf("%lld",&num);
return s[x].w=num%mod;//特色建树,到了叶子节点时再输入,然后传上去
}
ll mid=(L+R)/2;
return s[x].w=(build(x*2,L,mid)+build(x*2+1,mid+1,R))%mod;
}
void down(ll x)
{//具体的标记下传
s[x*2].add=(s[x].add+s[x*2].add*s[x].mul)%mod;
s[x*2+1].add=(s[x].add+s[x*2+1].add*s[x].mul)%mod;
s[x*2].mul=(s[x*2].mul*s[x].mul)%mod;
s[x*2+1].mul=(s[x*2+1].mul*s[x].mul)%mod;
s[x*2].w=(s[x*2].w*s[x].mul+s[x].add*(s[x*2].r-s[x*2].l+1))%mod;
s[x*2+1].w=(s[x*2+1].w*s[x].mul+s[x].add*(s[x*2+1].r-s[x*2+1].l+1))%mod;
s[x].add=0;
s[x].mul=1;
}
ll query(ll x,ll L,ll R)
{
down(x);
if(s[x].l>=L&&s[x].r<=R)//包含的话直接返回
return s[x].w%mod;
ll mid=(s[x].l+s[x].r)/2;//哪边有询问就加上哪边的询问值
return ((L<=mid?query(x*2,L,R):0)+(R>mid?query(x*2+1,L,R):0))%mod;
}
void update(ll x,ll v,ll typ,ll L,ll R)
{
down(x);
if(typ==1&&s[x].l>=L&&s[x].r<=R)//包含关系
{
s[x].mul=(s[x].mul*v)%mod;
s[x].add=(s[x].add*v)%mod;
s[x].w=(s[x].w*s[x].mul)%mod;//先乘再加
return;
}
if(typ==2&&s[x].l>=L&&s[x].r<=R)
{
s[x].add=(s[x].add+v)%mod;
s[x].w=(s[x].w+s[x].add*(s[x].r-s[x].l+1))%mod;
return;
}
ll mid=(s[x].l+s[x].r)/2;
if(L<=mid)
update(x*2,v,typ,L,R);
if(R>mid)
update(x*2+1,v,typ,L,R);
s[x].w=s[x*2].w+s[x*2+1].w;//最后更新父亲节点
}
main()
{
scanf("%lld%lld%lld",&n,&m,&mod);
build(1,1,n);
for(ll i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&typ,&x,&y);
if(typ!=3)
{
scanf("%lld",&k);
update(1,k,typ,x,y);
}
else
printf("%lld\n",query(1,x,y));
}
}