模板庫

hongou發表於2024-09-14

資料結構

莫隊

普通莫隊

題目來源:P1494 [國家集訓隊] 小 Z 的襪子。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 10;
struct node
{
    int l, r, id;
} q[N];
struct node2
{
    int c, s;
} ans[N];
int n, m;
int a[N], st[N], ed[N], vis[N], be[N];
int sum;
bool cmp(node x, node y)
{
    if (be[x.l] == be[y.l])
        return be[x.r] == be[x.r] ? (x.r < y.r) : (be[x.r] < be[y.r]);
    return be[x.l] < be[y.l];
}
void ins(int x)
{
    sum += (2 * vis[a[x]]);
    vis[a[x]]++;
}
void de(int x)
{
    sum = sum - 2 * vis[a[x]] + 2;
    vis[a[x]]--;
}
long long gcdd(long long a, long long b)
{
    return b != 0 ? gcdd(b, a % b) : a;
}
signed main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= m; i++)
        cin >> q[i].l >> q[i].r, q[i].id = i;
    int t = sqrt(m);
    for (int i = 1; i <= t; i++)
        st[i] = (i - 1) * t + 1, ed[i] = i * t;
    if (m > ed[t])
        t++, st[t] = ed[t - 1] + 1, ed[t] = n;
    for (int i = 1; i <= t; i++)
        for (int j = st[i]; j <= ed[i]; j++)
            be[j] = i;
    sort(q + 1, q + 1 + m, cmp);
    int l = 1, r = 0;
    for (int i = 1; i <= m; i++)
    {
        if (q[i].l == q[i].r)
        {
            ans[q[i].id] = {1, 0};
            continue;
        }
        while (l > q[i].l)
            ins(--l);
        while (r < q[i].r)
            ins(++r);
        while (l < q[i].l)
            de(l++);
        while (r > q[i].r)
            de(r--);
        long long x = (r - l + 1) * (r - l);
        long long y = sum;
        long long z = gcdd(x, sum);
        ans[q[i].id].c = x / z;
        ans[q[i].id].s = y / z;
    }
    for (int i = 1; i <= m; i++)
    {
        printf("%d/%d\n", ans[i].s, ans[i].c);
    }
    return 0;
}

樹上莫隊

問題求解樹上兩個節點 \(u,v\) 最短路徑上節點的權值中位數。

演算法:莫隊加分塊。

把樹變成括號序,記錄 \(dfn[i]\)\(id[0][i],id[1][i]\),表示括號序,括號序的對映。

詢問分兩種情況:

先保持:\(id[1][u]<=id[1][v]\),為了使 \(u\)\(v\) 前面。

  1. \(u,v\) 在兩個子樹內,\(q[i]={id[1][u],id[0][v],i}\),先上去(從 \(u\) 回溯開始)再下去(到 \(v\) 搜尋開始)。

  2. \(u,v\) 在一個子樹內,\(q[i]={id[0][v]+1,id[0][u],i}\)\(u\)\(v\) 中,從 \(v\) 走到 \(u\)

莫隊移動 \(l,r\) 時,如果 \(u\) 在不在 \(l,r\) 中,就執行原來的操作,如果不在就執行相反的。

void upd(int u,int op)
{
	(usd[u]&1)?del(u):ins(u);	
	usd[u]+=op?1:-1;
}

code:

#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int N=2e5+10;
int las[N],to[N],nxt[N],cnt,c[N],id[2][N],a[N];
int dfn[N],tot,col[N],usd[N],ss;
double ans[N];
int n,mm,maxx;
struct node2
{
	int l,r,id;
}q[N];
struct node
{
	int l[N],r[N],sum[N],len,m,be[N],B;
	void clear()
	{
		memset(sum,0,sizeof sum);
	}
	void init()
	{
		B=sqrt(len);
		m=len/B;
		for(int i=1;i<=m;i++)
			l[i]=(i-1)*B+1,r[i]=i*B;
		if(r[m]<len)
			l[m+1]=r[m]+1,r[++m]=len;
		for(int i=1;i<=m;i++)
			for(int j=l[i];j<=r[i];j++)	be[j]=i;
	}
}t,mid;
void add(int u,int v,int w)
{
	nxt[++cnt]=las[u];
	las[u]=cnt;
	to[cnt]=v;
	c[cnt]=w;
}
bool cmp(node2 a,node2 b)
{
	int la=a.l,lb=b.l,ra=a.r,rb=b.r;
	if(t.be[la]!=t.be[lb])return t.be[la]<t.be[lb];
	return ra<rb;	
}
void dfs(int u,int fa)
{
	dfn[++tot]=u;
	id[0][u]=tot;
	for(int e=las[u];e;e=nxt[e])
	{
		int v=to[e];
		if(v==fa)	continue;
		a[v]=c[e];
		dfs(v,u);
	}
	dfn[++tot]=u;
	id[1][u]=tot;
}
void ins(int x)
{
	x=a[x];
	col[x]++;
	mid.sum[mid.be[x]]++;
	ss++;
}
void del(int x)
{
	x=a[x];
	col[x]--;
	mid.sum[mid.be[x]]--;
	ss--;
}
void upd(int u,int op)
{
	(usd[u]&1)?del(u):ins(u);	
	usd[u]+=op?1:-1;
}
int get(int x)
{
	int now=0;
	for(int i=1;i<=mid.m;i++)
		if(mid.sum[i]+now>=x)
		{
			for(int j=mid.l[i];j<=mid.r[i];j++)
				if(now+col[j]>=x)	return j;
				else now+=col[j];
		}
		else now+=mid.sum[i];
			
}
void sovle()
{
	memset(las,0,sizeof las);
	memset(col,0,sizeof col);
	memset(usd,0,sizeof usd);
	t.clear(),mid.clear();
	cnt=ss=tot=0;
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w),add(v,u,w);
		maxx=max(maxx,w);
	}
	dfs(1,0);
	t.len=tot,mid.len=maxx;
	t.init(),mid.init();
	scanf("%d",&mm);
	for(int i=1;i<=mm;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		if(id[1][u]>id[1][v])	swap(u,v);
		if(id[0][u]<id[0][v])	q[i]={id[1][u],id[0][v],i};
		else q[i]={id[0][v]+1,id[0][u],i};
	}
	sort(q+1,q+1+mm,cmp);
	int l=1,r=0;
	for(int i=1;i<=mm;i++)
	{
		//cout<<q[i].l<<" "<<q[i].r<<endl;
		while(l>q[i].l)	upd(dfn[--l],1);
		while(r<q[i].r)	upd(dfn[++r],1);
		while(l<q[i].l)	upd(dfn[l++],0);
		while(r>q[i].r)	upd(dfn[r--],0);
		//cout<<ss<<endl;
		//for(int i=1;i<=maxx;i++)	cout<<col[i]<<" ";	cout<<endl;
		ans[q[i].id]=ss&1?get((ss+1)/2):(get(ss/2+1)+get(ss/2))/2.0;
		//cout<<"ans"<<ans[q[i].id]<<endl;
	}
	for(int i=1;i<=mm;i++)	printf("%.1lf\n",ans[i]);
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)	sovle();
	return 0;
 } 
 /*
多測的資料
2
6
1 2 9
2 5 5
2 4 7
3 5 1
3 6 4
3
1 3
4 6
2 6
6
1 2 9
2 5 5
2 4 7
3 5 1
3 6 4
3
1 3
4 6
2 6
 */

圖論

樹的基本知識

樹的重心

沒有模板題,用的會議這道題。

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
vector<int>e[N];
int n;
int siz[N],res,d[N],f[N];
void dfs(int u,int fa)
{
    siz[u]=1;
    mx=0;
    for(auto v : e[u])
    {
        if(v==fa)   continue;
        dfs(v,u);
        siz[u]+=siz[v];
        f[u]=max(siz[v],f[u]);
    }
    f[u]=max(n-siz[u],f[u]);
    if(f[u]<f[res]||(f[u]==f[res]&&res>u))    
        res=u;
}
void dfs2(int u,int fa)
{
    
    for(auto v : e[u])
    {
        if(v==fa)   continue;
        d[v]=d[u]+1;
        dfs2(v,u);
        
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    f[0]=1e9+10;
    dfs(1,0);
    dfs2(res,0);
    for(int i=1;i<=n;i++)
        ans+=d[i];
    printf("%d %d",res,ans);
}

重鏈剖分

兩次搜尋預處理。

void dfs1(int u,int fa)
{
    f[u]=fa;
    siz[u]=1;
    dep[u]=dep[fa]+1;
    for(int e=las[u];e;e=nxt[e])
    {
        int v=to[e];
        dfs1(v,u);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v])  son[u]=v; 
    }
}
void dfs2(int u,int tp_now)
{
    id[0][u]=++tim;
    dfn[tim]=u;
    tp[u]=tp_now;
    if(son[u]) 
        dfs2(son[u],tp_now);
    for(int e=las[u];e;e=nxt[e])
    {
        int v=to[e];
        if(son[u]==v||v==f[u])   continue;
        dfs2(v,v);
    }
    id[1][u]=tim;
}

線段樹區間操作時的跳鏈:

void upchange(int u,int v,int x)
{
//	cout<<"#####"<<endl;
    while(top[u]!=top[v])
    {
        if(dep[tp[u]]<dep[tp[v]])swap(u,v);
        change(1, id[0][tp[u]], id[0][u], x);
        u=f[tp[u]];
    }
    if(dep[u]>dep[v])swap(u,v);
    change(1, id[0][u], id[0][v], x);
        
}
int upask(int u,int v)
{
    int res=0;
    while(tp[u]!=tp[v])
    {
        if(dep[tp[u]]<dep[tp[v]])swap(u,v);
        res+=ask(1, id[0][tp[u]], id[0][u]);
        res%=mod;
        u=f[tp[u]];
    }
    if(dep[u]>dep[v])swap(u,v);
    res+=ask(1, id[0][u], id[0][v]);
    return res%mod;
}

最短路

Floyd

#include <bits/stdc++.h>
using namespace std;
const int N = 500 + 10, inf = 1e9 + 10;
int n, m;
int dis[N][N];
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (i != j)
                dis[i][j] = inf;
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        dis[u][v] = dis[v][u] = min(dis[u][v], w);
    }

    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                dis[i][j] = min(dis[i][k] + dis[k][j], dis[i][j]);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
            printf("%d ", dis[i][j]);
        puts("");
    }
    return 0;
}

dijstra

#include <bits/stdc++.h>
#define pii pair<long long, int>
typedef long long ll;
using namespace std;
const int N = 2e5 + 10;
int n, m, s;
ll dis[N];
bool vis[N];
vector<pii> e[N];
int main()
{
    scanf("%d%d%d", &n, &m, &s);
    for (int i = 1; i <= m; i++)
    {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        e[u].push_back({v, w});
        e[v].push_back({u, w});
    }
    priority_queue<pii, vector<pii>, greater<pii>> q;
    memset(dis, 0x3f, sizeof dis);
    dis[s] = 0;
    q.push({0, s});
    while (!q.empty())
    {
        int u = q.top().second;
        q.pop();
        if (vis[u])
            continue;
        vis[u] = 1;
        for (auto t : e[u])
        {
            int v = t.first, w = t.second;
            if (dis[v] > dis[u] + w)
                dis[v] = dis[u] + w, q.push({dis[v], v});
        }
    }
    for (int i = 1; i <= n; i++)
        printf("%lld ", dis[i]);
    return 0;
}

johnson

#include<bits/stdc++.h>
#define pii pair<int,int>
typedef long long ll;
using namespace std;
const int N=3e3+10,M=6e3+10;
const ll inf=1e18;
int n,m,num[N];
vector<pii>e[N];
ll dis[N],d[N];
bool vis[N];
bool spfa(int s)
{
    fill(dis,dis+n+1,inf);
    dis[s]=0,vis[s]=1;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(auto t : e[u])
        {
            int v=t.first,w=t.second;
            if(dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                if(!vis[v])
                {
                    q.push(v);
                    vis[v]=1;
                    num[v]++;
                    if(num[v]==n+1)
                        return 0;
                }
            }
        }
    }
    return 1;
}
void dij(int s)
{
    fill(d,d+1+n,inf);
    fill(vis,vis+1+n,0);
    d[s]=0;
    priority_queue<pii,vector<pii>,greater<pii> >q;
    q.push({0,s});
    while(!q.empty())
    {
        int u=q.top().second;
        q.pop();
        if(vis[u])  continue;
        vis[u]=1;
        for(auto t : e[u])
        {
            int v=t.first,w=t.second;
            if(d[v]>d[u]+w)
            {
                d[v]=d[u]+w;
                q.push({d[v],v});
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        e[u].push_back({v,w});
    }
    for(int i=1;i<=n;i++)
        e[n+1].push_back({i,0});
    if(!spfa(n+1))
        return puts("-1"),0;
    for(int i=1;i<=n;i++)
        for(auto &t: e[i])
            t.second+=dis[i]-dis[t.first];
    for(int i=1;i<=n;i++)
    {
        dij(i);
        ll ans=0;
        for(int j=1;j<=n;j++)
            if(d[j]==inf) ans+=1ll*1e9*j;
            else ans+=(d[j]+dis[j]-dis[i])*j;
        printf("%lld\n",ans);
    }
    return 0;
}

連通性問題

割點

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
vector<int>e[N];
int n,m;
int dfn[N],low[N],buc[N],tim;
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++tim;
    int son=0;
    for(auto v : e[u])
    {
        if(v==fa)   continue;
        if(!dfn[v])
        {
            son++,tarjan(v,u);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]&&fa!=0)   buc[u]=1;
        }
        else low[u]=min(low[u],dfn[v]);
    }
    if(son>=2&&fa==0)   buc[u]=1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v),e[v].push_back(u);
    }
    for(int i=1;i<=n;i++)
    {
        if(!dfn[i]) tarjan(i,0);
    }
    int ans=0;
    for(int i=1;i<=n;i++)   ans+=buc[i];
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)
        if(buc[i])  printf("%d ",i);
    return 0;
}

割邊

code:

#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int N=1e6+10;
int n,m;
vector<pii>e[N];
int tim,dfn[N],stk[N],top,low[N],tot;
vector<int>ans[N];
void form(int u)
{
    ++tot;
    do{ans[tot].push_back(stk[top]);}
    while(stk[top--]!=u);
}
void tarjan(int u,int fa)
{
    dfn[u]=low[u]=++tim;
    stk[++top]=u;
    for(auto t : e[u])
    {
        if(t.second==fa)    continue;
        int v=t.first;
        if(!dfn[v])
        {
            tarjan(v,t.second);
            low[u]=min(low[u],low[v]);
            if(dfn[u]<low[v])   form(v);
        }
        else low[u]=min(low[u],dfn[v]);
    }   
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back({v,i}),e[v].push_back({u,i});
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i,0),form(i);
    printf("%d\n",tot);
    for(int i=1;i<=tot;i++)
    {
        printf("%d ",ans[i].size());
        for(auto v : ans[i])    printf("%d ",v);
        puts("");
    }
    return 0;
}

樹上相關

最近公共祖先

倍增法(O(nlogn)-O(logn)):

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
struct getlca
{
    int las[N],to[N],cut,nxt[N],c[N];
    
    int dep[N],f[N][20];
    void add(int u,int v)
    {
        cut++;
        nxt[cut]=las[u];
        las[u]=cut;
        to[cut]=v;
    }
    void init(int u,int fa)
    {
        dep[u]=dep[fa]+1;
        f[u][0]=fa;
        for(int i=1;i<=19;i++)
        f[u][i]=f[f[u][i-1]][i-1];
        for(int e=las[u];e;e=nxt[e])
        {
            int v=to[e];
            if(fa==v)continue;
            init(v,u);
        }
    }
    int lca(int u,int v)
    {
        if(dep[u]<dep[v])swap(u,v);
        for(int i=19;i>=0;i--)
        if(dep[u]-(1<<i)>=dep[v])u=f[u][i];
        if(v==u) return u;
        for(int i=19;i>=0;i--)
        {
            if(f[u][i]!=f[v][i])
            u=f[u][i],v=f[v][i];
        }
        return f[u][0];
    }
}T;
int n,m,st;
int main()
{
	cin>>n>>m>>st;
	for(int i=1;i<n;i++)
	{
		int u,v;
		cin>>u>>v;
		T.add(u,v),T.add(v,u);
	}
	T.init(st,0);
	while(m--)
	{
		int u,v;
		cin>>u>>v;
		cout<<T.lca(u,v)<<endl;
	}
	return 0;
}

tarjan(離線)(O(n)-O(n)):

#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int N=5e5+10;
int n,m,s;
vector<int>e[N];
vector<pii>q[N];
int fa[N],dep[N],ans[N];
bool vis[N];
int find(int x)
{
    if(x==fa[x])    return x;
    return fa[x]=find(fa[x]);
}
void uni(int x,int y)
{
    x=find(x),y=find(y);
    if(dep[x]>dep[y])   fa[x]=y;
    else fa[y]=x;
}
void tarjan(int u,int fa)
{
    dep[u]=dep[fa]+1;
    vis[u]=1;
    for(auto v : e[u])
    {
        if(v==fa)   continue;
        tarjan(v,u);
        uni(u,v);
    }
    for(auto t : q[u])
        if(vis[t.first])    ans[t.second]=find(t.first);
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=n;i++)   fa[i]=i;
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        q[u].push_back({v,i});
        q[v].push_back({u,i});
    }
    tarjan(s,0);
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}

dfs 序 + st 表(O(nlogn)-O(1)):

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
vector<int>e[N];
int n,m,s;
struct getlca
{
    int f[20][N],tot=0,dfn[N];
    void init(int u,int fa)
    {
        dfn[u]=++tot;
        f[0][tot]=fa;
        for(auto v : e[u])
        {
            if(v==fa)   continue;
            init(v,u);
        }
    }
    int get(int u,int v){return dfn[u]<dfn[v]?u:v;}
    int lca(int u,int v)
    {
        if(u==v)    return u;
        if(dfn[u]>dfn[v])   swap(u,v);
        u=dfn[u]+1,v=dfn[v];
        int t=log2(v-u+1);
        return get(f[t][u],f[t][v-(1<<t)+1]);
    }
}T;
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    T.init(s,0);
    for(int i=1;i<=19;i++)
        for(int j=1;j<=n;j++)
            T.f[i][j]=T.get(T.f[i-1][j],T.f[i-1][j+(1<<i-1)]);
    while(m--)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        printf("%d\n",T.lca(u,v));
    }
    return 0;
}

網路流

最大流

dinic 演算法。

#include<bits/stdc++.h>
using namespace std;
const int N=200+10,M=5e3+10;
int n,m,S,T;
struct dinic
{
    int las[N],to[M<<1],nxt[M<<1],lim[M<<1],cnt=1;
    void add(int u,int v,int li)
    {
        nxt[++cnt]=las[u];
        las[u]=cnt;
        to[cnt]=v;
        lim[cnt]=li;
    }
    int cur[N],dis[N],fr[N],fl[N];
    long long dfs(int u,long long res)
    {
        if(u==T)    return res;
        long long flow=0;
        for(int i=las[u];i&&res;i=nxt[i])
        {
            cur[u]=i;
            int c=min((long long)lim[i],res),v=to[i];
            if(dis[v]==dis[u]+1&&c)
            {
                int k=dfs(v,c);
                flow+=k,lim[i]-=k,lim[i^1]+=k,res-=k;
            }
        }
        if(!flow)   dis[u]=-1;
        return flow;
    }
    long long maxflow(int s,int t)
    {
        long long flow=0;
        while(1)
        {
            memcpy(cur,las,sizeof las);
            memset(dis,-1,sizeof dis);
            queue<int>q;
            q.push(s);
            dis[s]=0;
            while(!q.empty())
            {
                int u=q.front();q.pop();
                for(int i=las[u];i;i=nxt[i])
                {
                    int v=to[i];
                    if(lim[i]&&dis[v]==-1)
                    {
                        dis[v]=dis[u]+1;
                        q.push(v);
                    }
                }
            }
            if(dis[t]==-1)  return flow;
            flow+=dfs(s,1e18);
        }
    }
}G;
int main()
{
    scanf("%d%d%d%d",&n,&m,&S,&T);
    for(int i=1;i<=m;i++)
    {
        int u,v,li;
        scanf("%d%d%d",&u,&v,&li);
        G.add(u,v,li),G.add(v,u,0);
    }
    printf("%lld",G.maxflow(S,T));
    return 0;
}

最小費用最大流

SSP 演算法。

注意點:

  1. 鏈式前向星的 cnt 一定從 \(1\) 開始,因為要成對變換。

  2. 每增廣路一次就要初始化。

  3. SPFA 在隊首為 \(T\) 時不能直接 break,因為第一次取出 \(T\)\(dis[T]\) 不一定取到最短路。

#include<bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int N=5e3+10,M=5e4+10;
int n,m,S,T;
struct SSP
{
    int las[N],nxt[M<<1],to[M<<1],c[M<<1],lim[M<<1],cnt=1;
    void add(int u,int v,int w,int li)
    {
        nxt[++cnt]=las[u];
        las[u]=cnt;
        to[cnt]=v;
        c[cnt]=w;
        lim[cnt]=li;
    }
    int fl[N],fr[N],vis[N],dis[N];
    pii mincost(int s,int t)
    {
        int flow=0,cost=0;
        while(1)
        {
            memset(dis,0x3f,sizeof dis);
            memset(vis,0,sizeof vis);
            dis[s]=0,fl[s]=1e9;
            queue<int>q;
            q.push(s);
            vis[s]=1;
            while(!q.empty())
            {
                int u=q.front();q.pop();
                vis[u]=0;
                for(int i=las[u];i;i=nxt[i])
                {
                    int v=to[i];
                    if(dis[v]>dis[u]+c[i]&&lim[i])
                    {
                        dis[v]=dis[u]+c[i];
                        fr[v]=i;
                        fl[v]=min(fl[u],lim[i]);
                        if(!vis[v]) vis[v]=1,q.push(v);
                    }
                }
            }            
            if(dis[t]>1e9)  return {flow,cost};
            flow+=fl[t],cost+=fl[t]*dis[t];
            for(int u=t;u!=s;u=to[fr[u]^1])
                lim[fr[u]]-=fl[t],lim[fr[u]^1]+=fl[t];
        }
    }
    
}G;
int main()
{
    scanf("%d%d%d%d",&n,&m,&S,&T);
    for(int i=1;i<=m;i++)
    {
        int u,v,w,li;
        scanf("%d%d%d%d",&u,&v,&li,&w);
        G.add(u,v,w,li),G.add(v,u,-w,0);
    }
    auto ans=G.mincost(S,T);
    printf("%d %d",ans.first,ans.second);
    return 0;
}

數學

矩陣相關

高斯消元

SDOI2006 線性方程組為模板。

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
double a[110][110];
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n+1;j++)
            cin>>a[i][j];
    int r=1;
    for(int i=1;i<=n;i++)
    {
        int t=r;
        for(int j=r+1;j<=n;j++)
            if(fabs(a[j][i])>fabs(a[t][i])) t=j;
        if(fabs(a[t][i])<eps)   continue;
        for(int j=i;j<=n+1;j++)  
            swap(a[r][j],a[t][j]);
        for(int j=n+1;j>=i;j--)
            a[r][j]/=a[r][i];
        for(int j=r+1;j<=n;j++)
            for(int z=n+1;z>=i;z--)
                a[j][z]-=a[j][i]*a[r][z];
        r++;
    }
    if(r<=n)
    {
        for(int i=r;i<=n+1;i++)
            if(fabs(a[i][n+1])>eps)
                return puts("-1"),0;
        return puts("0"),0;
    }
    for(int i=n-1;i>=1;i--)
        for(int j=i+1;j<=n;j++)
            a[i][n+1]-=a[j][n+1]*a[i][j];
    for(int i=1;i<=n;i++)
        printf("x%d=%.2lf\n",i,a[i][n+1]);
    return 0;
}

同餘相關

擴充套件中國剩餘定理

#include<bits/stdc++.h>
using namespace std;
typedef __int128_t ll;
const int N=1e7+10;
ll gcd(ll aa,ll bb)
{
    if(!bb) return aa;
    return gcd(bb,aa%bb);
}
ll lcm(ll aa,ll bb)
{
    return aa/gcd(aa,bb)*bb;
}
ll exgcd(ll aa,ll bb,ll &x,ll &y)
{
    if(!bb)
    {
        x=1,y=1;
        return aa;
    }
    ll d=exgcd(bb,aa%bb,x,y);
    ll z=x;
    x=y;
    y=z-(aa/bb)*y;
    return d;
}
long long a[N],b[N],n;
int main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld%lld",&a[i],&b[i]);
    ll a1=a[1],b1=b[1];
    for(int i=2;i<=n;i++)
    {
        ll a2=a[i],b2=b[i],x,y;
        ll c=b2-b1;
        ll d=exgcd(a1,a2,x,y);
        if(c%d)
            return puts("-1"),0;
        c/=d;
        x=x*c%(a2/d);
        if(x<0) x+=(a2/d);
        ll mod=lcm(a1,a2);
        b1=(a1*x+b1)%mod;
        if(b1<mod)  b1+=mod;
        a1=mod;
          //printf("a b %lld %lld\n",(long long)a1,(long long)b1);
    }
    printf("%lld",(long long)((b1%a1)+a1)%a1);
    return 0;
}

相關文章