板子

目录

矩阵快速幂

最短路

最大流/最小割

二分图最大独立集

强连通分量

 


  • 矩阵快速幂

#include 
#define ll long long
using namespace std;
const int maxn = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
struct Matrix{
	ll  m[2][2];
} ans,rec; 
ll n,mod;
ll x0,x1,a,b;
Matrix Mul(Matrix a, Matrix b){
	Matrix c;
	for(int i=0;i<2;i++)
      for(int j=0;j<2;j++)  
          c.m[i][j]=0;     
   for(int i=0;i<2;i++)
     for(int j=0;j<2;j++){
       for(int k=0;k<2;k++)
          c.m[i][j]+=a.m[i][k]*b.m[k][j]; 
     c.m[i][j]=c.m[i][j]%mod;
     } 
     return c;           
}
Matrix pow(ll x){
	Matrix ans; 
	for(int i=0;i<2;i++)
	  for(int j=0;j<2;j++){ 
	       if(i==j)
	      ans.m[i][j]=1;
	      else 
	      ans.m[i][j]=0;
	   } 	      
	 while(x){
	 	if(x%2)
	       ans=Mul(ans,rec);	
	 	rec=Mul(rec,rec);
	 	x=x/2;
	 } 	
	 return ans;
}
int main(){
	cin>>x0>>x1>>a>>b;
	cin>>n>>mod;
	rec.m[0][0]=a;rec.m[0][1]=b;
	rec.m[1][0]=1;rec.m[1][1]=0;
	Matrix tmp=pow(n-1);
	cout<<(tmp.m[0][0]+tmp.m[0][1])%mod<
  • 最短路

  1. (dijstra+堆优化) O(ElogV) 无法处理负边情况

堆优化加前向星邻接表板子
 struct Edge{
	int v,w;//w为距离 
	int next;
};
Edge edge[maxn];
struct qnode{    //堆优化 
     int u;	
     int w;
     
   qnode(int u=0,int w=0):u(u),w(w){}//构造函数 
  
	bool operator < (const qnode& a) const{//重载小于号 
	return w>a.w;
	} 
};
long long dis[maxn];
int head[maxn];
bool vis[maxn];
int size; 
void add_edge(int u,int v,int w){//
	  edge[size].v=v;
	  edge[size].w=w;
	  edge[size].next=head[u];
	  head[u]=size;
	  size++; 
}
void dijkstra(int s){
	priority_queueq;
	while(!q.empty())
	q.pop();
	
    q.push(qnode(s,0));
	dis[s]=0;

	while(!q.empty()){
		qnode t=q.top();
		q.pop();
		int u=t.u;
		if(vis[u])continue;
		vis[u]=true;
		for(int i=head[u];i!=-1;i=edge[i].next){
			int v=edge[i].v;
			int w=edge[i].w; 
			if(!vis[v]&&dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push(qnode(v,dis[v])); 
			} 
		}	
	}
}
for(int i=1;i<=n;i++){//初始化 
	head[i]=-1;
	dis[i]=inf;
	vis[i]=false; 
}
  • 最大流/最小割

#include 
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1000000;
typedef long long ll;
const int N = 20005;
const ll INF = 0x3f3f3f3f3f3f3f3f;
bool vis[N];
struct Edge{
    int to;
	ll cap, flow;
	int next;//邻接点,容量,流量,next
}edge[N*50];
int n, m, cnt;//n是点 m是边 cnt是加边操作后的边 
int head[N];//邻接表 
int dis[N];//分层 等级 
int  cur[N];//弧优化 
void add(int u, int v, ll w){
    edge[cnt] = (struct Edge){v, w, 0, head[u]};
    head[u] = cnt++;
    edge[cnt] = (struct Edge){u, 0, 0, head[v]};
    head[v] = cnt++;
}
 
bool bfs(int start, int endd){//分层 
    memset(dis, -1, sizeof(dis));
    memset(vis, false, sizeof(vis));
    queueque;
    dis[start] = 0;
    vis[start] = true;
    que.push(start);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = head[u]; i != -1; i = edge[i].next){
            Edge E = edge[i];
            if(!vis[E.to] && E.flow0){
                edge[i].flow += f;
                edge[i^1].flow -= f;
                flow += f;
                res -= f;
                if(res == 0) break;
            }
		}
	}
	return flow;
}

ll max_flow(int start, int endd){
    ll flow = 0;
    while(bfs(start, endd)){
        memcpy(cur, head, sizeof(head));//初始化弧优化数组 
        flow += dfs(start, INF, endd);
    }
    return flow;
}
void init(){//初始化 
    cnt = 0;
    memset(head, -1, sizeof(head));
}
int main(){
    scanf("%d%d", &n, &m);
    init();
    int sp=1;//源点 
    int tp=n;//汇点 
    for(int i = 1; i <= m; i++){
    	int x,y;
		ll z;
        scanf("%d%d%lld",&x,&y,&z);
        add(x, y, z);
    }    
    ll ans = max_flow(sp, tp);
    printf("%lld\n", ans);
    return 0;
}
  • 二分图最大独立集

#include 
#define ll long long
using namespace std;
const int maxn = 5e3+5;//点 
const int N = 3e7+5;//边 
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
int a[maxn];
int oddvis[maxn];//仅仅是为了区分左右集,该题是标记为左集,与此模板无关
bool vis[maxn];
struct Edge{
    int to;
    int cap, flow;
    int next;
}edge[N];
int cnt;
int head[maxn];
int dis[maxn];
int cur[maxn];
void add(int u, int v, int w){
    edge[cnt] = (struct Edge){v, w, 0, head[u]};
    head[u] = cnt++;
    edge[cnt] = (struct Edge){u, 0, 0, head[v]};
    head[v] = cnt++;
}
bool bfs(int start, int endd){
    memset(dis, -1, sizeof(dis));
    memset(vis, false, sizeof(vis));
    queueque;
    dis[start] = 0;
    vis[start] = true;
    que.push(start);
    while(!que.empty()){
        int u = que.front();
        que.pop();
        for(int i = head[u]; i != -1; i = edge[i].next){
            Edge E = edge[i];
            if(!vis[E.to] && E.flow0){
                edge[i].flow += f;
                edge[i^1].flow -= f;
                flow += f;
                res -= f;
                if(res == 0) break;
            }
        }
    }
    return flow;
}
int max_flow(int start, int endd){
    int flow = 0;
    while(bfs(start, endd)){
        memcpy(cur, head, sizeof(head));
        flow += dfs(start, INF, endd);
    }
    return flow;
}
void init(){
    cnt = 0;
    memset(head, -1, sizeof(head));
}

int main(){
    std::ios::sync_with_stdio(false);
    int n;
    cin>>n;
    int s=0;//建边 
    int e=n+1;
    init();
    ////////////////建图 重写////////////
   
    ////////////////////////////////////
    int num=max_flow(s,e);//二分图最大匹配 
    cout<
  • 强连通分量

  1. O(n+m)
#include 
#include 
#include 
#include 
using namespace std;
int n,m,idx=0,cnt=1,Bcnt=0;
int head[100];
int vis[100];
int dfn[100],low[100];
int Belong[100];//belong表示每个点属于缩完之后的哪一个点
stack  s;
struct edge{
    int v,next;
}e[100];
void adde(int u,int v){
	e[cnt].next=head[u];
    e[cnt].v=v;
    head[u]=cnt++;
}
void readdata(){
    int a,b;
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        adde(a,b);
    }
}
void tarjan(int u){
    int v;
    dfn[u]=low[u]=++idx;//
    s.push(u);//将u入栈
    vis[u]=1;//标记u在栈内
    for(int i=head[u];i!=-1;i=e[i].next){
        v=e[i].v;
        if(!dfn[v]){
            tarjan(v);//dfs(v)
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
		    low[u]=min(low[u],dfn[v]);
    }     
    if(dfn[u]==low[u]){//发现是整个强连通分量子树里的最小根。
        Bcnt++;
        do{             //具体处理强连通分量时改这里 
            v=s.top();
            s.pop();
            vis[v]=0;//表示出栈 
            Belong[v]=Bcnt;
        }while(u != v);
    }
}
void work(){
    for(int i=1;i<=n;i++)  if(!dfn[i]) tarjan(i);//保证每个点去找 
    printf("\n");
    for(int i = 1;i <= 6;i++) printf("%d %d\n",dfn[i],low[i]);
    printf("共有%d强连通分量,它们是:\n",Bcnt); 
    for(int i=1;i<=Bcnt;i++){
        printf("第%d个:",i);
        for(int j=1;j<=n;j++){
            if(Belong[j]==i) 
		printf("%d ",j);
            }
            printf("\n");
    }
}
int main(){
    readdata();
    work();
    return 0;
}
    /*
    6 8 
    1 2
    1 3
    2 4
    3 4
    3 5
    4 1
    4 6 
    5 6
    */
  • 主席树(区间第K小)

#include
#include
#include
#include
#include
#include
#include 
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
vector v;
struct node{
	int l;
	int r;
	int sum;
}T[maxn*50];
int n,m,a[maxn],root[maxn],x,y,k,cnt;//cnt是第几棵树 root是存的第几棵树的根节点编号 
int getid(int x){//得到离散化后的下标 
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos){//处理的下标   &能改变原有的数 
	T[++cnt]=T[y];//++cnt给新结点编号    主席树相当于前缀,所以记下上一个树节点的值 相当于pre[i]=pre[i-1] 
	T[cnt].sum++;//这一步相当于pre[i]=pre[i-1]+a[i]中的a[i] 因为主席树记的是数的个数  可持久化权值线段树 
	x=cnt;       //y是x前面一棵树 
	if(l==r)  return ;
	int mid=(l+r)/2;
	if(pos<=mid) update(l,mid,T[x].l,T[y].l,pos);//若K小于等与mid,则两棵树共用右树 
	else update(mid+1,r,T[x].r,T[y].r,pos);//反之 
}
int quert(int l,int r,int x,int y,int k){//返回的是离散后第K大下标 
	if(l==r) return l;
	int mid=(l+r)/2;
	int s=T[T[y].l].sum-T[T[x].l].sum;//是线段树左儿子的在区间[x,y]之内有多少个数; 
	if(k<=s) return quert(l,mid,T[x].l,T[y].l,k);//左子树足够找这K个数了 
	else return quert(mid+1,r,T[x].r,T[y].r,k-s);
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
        v.push_back(a[i]);
	}
	sort(v.begin(),v.end());//离散化 
	v.erase(unique(v.begin(),v.end()),v.end());//去重 
    for(int i=1;i<=n;i++){
    	update(1,v.size(),root[i],root[i-1],getid(a[i]));
	}
	for(int i=0;i>x>>y>>k;           //核心就是根据前缀和求差来计算   
		cout<

持续更新

 

你可能感兴趣的:(板子)