模板
模板整理(持续整理中)
基础算法
二分
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&∑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;
}
计算几何
本博文为wweiyi原创,若想转载请联系作者,qq:2844938982