欢迎各位读者发评论补充(我会标明补充者的博客和链接)
上一页:C++竞赛常用实用代码(2)
目录
下一页:C++竞赛常用实用代码(4)
可运算的矩阵结构体
struct matrix{
int n,m;
long long c[105][105];
matrix(){memset(c,0,sizeof(c));}
void read(){//读入矩阵
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%lld",&c[i][j]);
}
matrix operator*(const matrix&a){//矩阵乘法
matrix r;r.n=n,r.m=a.m;
for(int i=1;i<=r.n;i++)
for(int j=1;j<=r.m;j++)
for(int k=1;k<=m;k++)r.c[i][j]+=c[i][k]*a.c[k][j];
return r;
}
matrix operator*(const long long&a){//矩阵数乘
matrix r;r.n=n,r.m=m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)r.c[i][j]=c[i][j]*a;
return r;
}
matrix operator+(const matrix&a){//矩阵加法
matrix r=a;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)r.c[i][j]+=c[i][j];
return r;
}
matrix operator-(const matrix&a){//矩阵减法
matrix r;r.n=n,r.m=m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)r.c[i][j]=c[i][j]-a.c[i][j];
return r;
}
matrix mpow(matrix a,int b){//矩阵快速幂
matrix res;res.n=res.m=a.n;
for(int i=1;i<=res.n;i++)res.c[i][i]=1;
for(;b;b>>=1){
if(b&1)res=res*a;
a=a*a;
}
return res;
}
void print(){//输出
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)printf("%lld ",c[i][j]);
putchar('\n');
}
}
};
快速开方(不常用)
转自https://blog.csdn.net/qq_26499321/article/details/73724763
float InvSqrt(float x)//比标准的sqrt还快
{
float xhalf = 0.5f*x;
int i = *(int*)&x;
i = 0x5f375a86- (i>>1);
x = *(float*)&i;
x = x*(1.5f-xhalf*x*x);
x = x*(1.5f-xhalf*x*x);
x = x*(1.5f-xhalf*x*x);
return 1/x;
}
/*
int i = *(int*)&x; 这条语句把 x 转成 i=I_x 。
i = 0x5f375a86 - (i>>1); 这条语句从 I_x 计算 I_{1/\sqrt{x}} 。
x = *(float*)&i; 这条语句将 I_{1/\sqrt{x}} 转换为 1/\sqrt{x} 。
x = x*(1.5f - xhalf*x*x); 这时候的x是近似解;此步就是经典的牛顿迭代法。迭代次数越多越准确。
*/
乘法防爆(O(log)龟速乘)
inline long long qcheng(long long x,long long y){
long long res=0;
for(;y;y>>=1){
if(y&1)res=(res+x)%MOD;
(x<<=1)%=MOD;
}
return res;
}
*升级版*乘法防爆(O(1)光速乘)
#define ll long long
inline ll ksc(ll a,ll b){ //MOD为1e18左右的模数
long double z=(long double)a/MOD*b+1e-8;
ll x=a*b,y=(ll)z*MOD;x-=y;
if(x<0)x+=MOD;
return x;
}
说明:不保证结果100%正确,但是正确率极高,用过的人基本没有出锅的
tarjan缩点板子
vector<int>G[MAXN];
int dfn[MAXN],low[MAXN],belong[MAXN],IN,num;
stack<int>st;
void tarjan(int x){ //核心
low[x]=dfn[x]=++IN;
st.push(x);
for(int i=0,v;i<G[x].size();i++){
v=G[x][i];
if(!belong[v]){
if(!dfn[v]){
tarjan(v);
low[x]=min(low[x],low[v]);
}
else low[x]=min(low[x],dfn[v]);
}
}
if(low[x]==dfn[x]){
int out;
num++;
do{
out=st.top();
st.pop();
belong[out]=num;
}while(!st.empty()&&out!=x);
}
}
SPFA最短路&判负环板子
vector<int>G[MAXN];
int f[MAXN],v[MAXN];
bool inq[MAXN],error_; //error_表示有无负环
inline void spfa(int s){ //核心
memset(f,0x3f3f3f3f,sizeof(f));
queue<int>q;
q.push(s);
inq[s]=1,f[s]=0;
while(!q.empty()){
int u=q.front();
q.pop();
inq[u]=0;
if(v[u]>=n){
error_=1;
continue;
}
v[u]++;
for(int i=0,v;i<G[u].size();i++){
v=G[u][i];
if(f[v]>f[u]+1){
f[v]=f[u]+1;
if(!inq[v]){
q.push(v),inq[v]=1;
}
}
}
}
}
求LCA
倍增(建立O(nlogn),查询O(logn))
vector<int>G[MAXN];
int f[MAXN][30],d[MAXN];
void dfs(int x){ //预处理
d[x]=d[f[x][0]]+1;
for(int i=1;(1<<i)<d[x];i++)f[x][i]=f[f[x][i-1]][i-1];
for(int i=0;i<G[x].size();i++){
if(G[x][i]!=f[x][0]){
f[G[x][i]][0]=x;
dfs(G[x][i]);
}
}
}
inline int LCA(int a,int b){
if(d[a]>d[b])swap(a,b);
for(int i=20;i>=0;i--)
if(d[f[b][i]]>=d[a])b=f[b][i];
for(int i=20;i>=0;i--)
if(f[a][i]!=f[b][i])a=f[a][i],b=f[b][i];
return f[a][0];
}
树链剖分(建立O(n),查询O(logn))
int d[MAXN],hson[MAXN],tp[MAXN],id[MAXN],fa[MAXN];
vector<int>G[MAXN];
inline int dfs1(int x){
int siz=1,hs=0;d[x]=d[fa[x]]+1;
for(int i=0;i<G[x].size();i++)
if(G[x][i]!=fa[x]){fa[G[x][i]]=x;
int si=dfs1(G[x][i]);siz+=si;
if(si>hs)hs=si,hson[x]=G[x][i];
}
return siz;
}
inline void dfs2(int x){
id[x]=++IN;
if(x==hson[fa[x]])tp[x]=tp[fa[x]];
else tp[x]=x;
if(hson[x]>0)dfs2(hson[x]);
for(int i=0;i<G[x].size();i++)
if(G[x][i]!=fa[x]&&G[x][i]!=hson[x])dfs2(G[x][i]);
}
inline int lca(int u,int v){
while(tp[u]!=tp[v]){
if(d[tp[u]]>d[tp[v]])u=fa[tp[u]];
else v=fa[tp[v]];
}
return d[u]>d[v]?v:u;
}
欧拉序ST表(建立O(nlogn),查询O(1))
int d[MAXN],id[MAXN],st[MAXN<<1][25],R;
vector<int>G[MAXN];
inline int MIN(int x,int y){return d[x]<d[y]?x:y;}
inline void dfs(int x){
id[x]=++R,st[id[x]][0]=x;
for(int i=0;i<G[x].size();i++){
d[G[x][i]]=d[x]+1,dfs(G[x][i]);
st[++R][0]=x;
}
}
inline void build(){
for(int i=R;i>0;i--)
for(int j=1;j<=20&&i+(1<<j)-1<=R;j++)
st[i][j]=MIN(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
inline int lca(int u,int v){
int l=id[u],r=id[v],k;
if(l>r)swap(l,r);
k=int(log(r-l+1)/log(2));
return MIN(st[l][k],st[r-(1<<k)+1][k]);
}
ST表求最值板子
int stmax[MAXN][30],stmin[MAXN][30],a[MAXN];
inline void make(){
for(int i=1;i<=n;i++)stmax[i][0]=stmin[i][0]=a[i];
for(int i=n;i>0;i--)
for(int j=1;i+(1<<j)-1<=n;j++){
stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<j-1)][j-1]);
stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<j-1)][j-1]);
}
}
inline int Max(int l,int r){
int k=int(log(double(r-l+1))/log(2.0));//log函数要加头文件cmath
return max(stmax[l][k],stmax[r-(1<<k)+1][k]);
}
inline int Min(int l,int r){
int k=int(log(double(r-l+1))/log(2.0));
return min(stmin[l][k],stmin[r-(1<<k)+1][k]);
}
主席树求区间k小板子(不修改)
struct itn{int lson,rson,w;}tr[MAXN<<4];
inline void build(int x,int l,int r){//简单建树
if(l==r)return;
int mid=l+r>>1;
tr[x].lson=++IN,tr[x].rson=++IN;
build(tr[x].lson,l,mid),build(tr[x].rson,mid+1,r);
}
inline void add(int x,int y,int a){//新建一条链(非递归版)
int l=1,r=n,mid;
while(1){
tr[x].w=tr[y].w+1,mid=l+r>>1;
if(l==r)break;
if(a<=mid){
tr[x].lson=++IN,tr[x].rson=tr[y].rson;
x=tr[x].lson,y=tr[y].lson,r=mid;
}
else{
tr[x].rson=++IN,tr[x].lson=tr[y].lson;
x=tr[x].rson,y=tr[y].rson,l=mid+1;
}
}
}
inline int _find(int x,int y,int k){//单点查询(非递归版)
int l=1,r=n,mid;
while(1){
mid=l+r>>1;
if(l==r)return l;
int ls=tr[tr[x].lson].w-tr[tr[y].lson].w;
if(k<=ls)x=tr[x].lson,y=tr[y].lson,r=mid;
else x=tr[x].rson,y=tr[y].rson,l=mid+1,k-=ls;
}
}
//用法
build(++IN,1,n);
root[i]=++IN,add(root[i],root[i-1],a[i]);
ans=_find(root[r],root[l-1],k);
(nlogn)优化Dijkstra
堆优化
int s[MAXN];
struct node{int v,w;};
vector<node>G[MAXN];
struct cmp{bool operator()(int a,int b){return s[a]>s[b];}};//一行cmp
inline void dijkstra(int S){
priority_queue<int,vector<int>,cmp>q;
memset(s,0x7f,sizeof(s));
s[S]=0,q.push(S);
while(!q.empty()){
int u=q.top();q.pop();
for(int i=0;i<G[u].size();i++){
int v=G[u][i].v,w=G[u][i].w;
if(s[u]+w<s[v])s[v]=s[u]+w,q.push(v);
}
}
}
线段树优化
int s[MAXN],n,p,tr[MAXN*3];//zkw线段树
struct node{int v,w;};
vector<node>G[MAXN];
inline void build(){
for(p=1;p<n+2;p<<=1);
for(int i=1;i<=n;i++)tr[p+i]=i;
}
inline void change(int x,int d){
for(s[x]=d,x=p+x>>1;x>0;x>>=1)
tr[x]=s[tr[x<<1]]<s[tr[x<<1|1]]?tr[x<<1]:tr[x<<1|1];
}
inline void dijkstra(int S){
memset(s,0x7f,sizeof(s));
build(),change(S,0);
for(int q=1;q<n;q++){
int u=tr[1];tr[p+u]=0,change(u,s[u]);//打标记避重
for(int i=0;i<G[u].size();i++){
int v=G[u][i].v,w=G[u][i].w;
if(s[u]+w<s[v])change(v,s[u]+w);
}
}
}
zkw线段树详见:https://blog.csdn.net/weixin_43960287/article/details/108246164