模板

快读

char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    return x*f;
}

操作1: 1 x 表示将x插入到堆中

操作2: 2 输出该小根堆内的最小数

操作3: 3 删除该小根堆内的最小数

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
int n,x;
int read() {
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int main() {
    n=read();
    for(int i=1; i<=n; i++) {
        x=read();
        if(x==1) {
            x=read();
            q.push(x);
        } else if(x==2) printf("%d
",q.top());
        else q.pop();
    }
}
View Code

最长公共子序列

#include<iostream>
#include<cstdio>
using namespace std;
int a[100001],b[100001],map[100001],f[100001];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){scanf("%d",&a[i]);map[a[i]]=i;}
    for(int i=1;i<=n;i++){scanf("%d",&b[i]);f[i]=0x7fffffff;}
    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)/2;
            if(f[mid]>map[b[i]])r=mid;
            else l=mid+1; 
        }
        f[l]=min(map[b[i]],f[l]);
        }
    }
    cout<<len;
    return 0
}
View Code

前向星

struct node{
    int to, nxt, l;
}e[maxn << 1];
int head[maxn], tot = 0;
void addedge(int u, int v, int l){
    e[++tot].to = v, e[tot].nxt = head[u], e[tot].l = l;
    head[u] = tot;
}
View Code

割点

void tarjan(int u,int fa){
    dfn[u]=low[u]=++now;
    int child=0;
    for(int i=head[u];i!=0;i=edge[i].nxt){
        int Next=edge[i].to;
        if(dfn[Next]==0){
            tarjan(Next,fa);
            low[u]=min(low[u],low[Next]);
            if (low[Next]>=dfn[u]&&u!=fa)
                cut[u]=1;
            if(u==fa)
                child++;
        }
        low[u]=min(low[u],dfn[Next]);
    }
    if(child>=2 && u==fa)
        cut[u]=1;
}
int work(){
    for(int i=1;i<=m;i++)
        if(dfn[i]==0)
            tarjan(i,i);
}
View Code

拓扑

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int indegree[100];
int n,m;
bool map[100][100];
int a[100];
int topu()
{
    queue<int> q;
    int cnt = 1;
    while(!q.empty())//清空队列
        q.pop();
    for(int i = 1; i <= n ; i++)
        if(indegree[i] == 0)
            q.push(i);//将 没有依赖顶点的节点入队
    int u;
    while(!q.empty())  //
    {
        u = q.front();
        a[cnt++] = u;//将上边选出的没有依赖顶点的节点加入到排序结果中
        q.pop();//删除队顶元素 
        for(int i = 1; i <= n ; i++)
        {
            if(map[u][i])
            {
                indegree[i] --;//删去以u为顶点的边
                if(indegree[i] == 0) //如果节点i的所有依赖顶点连接边都已经删去
                    q.push(i);  //即变为无依赖顶点的节点   将其入队
            }
        }
        if(cnt == n+1)//如果排序完成输出结果
        {
            for(int i = 1 ; i <= n ; i++)
                printf(" %d",a[i]);
        }
    }
}
int main()
{
    int u,v;
    while(~scanf("%d%d",&n,&m))
    {
        memset(indegree,0,sizeof(indegree));
        memset(map,0,sizeof(map));
        for(int i = 0 ; i < m ; i++)
        {
            scanf("%d%d",&u,&v);
            if(!map[u][v])//考虑重边
            {
                indegree[v]++;//连接v的边的条数
                map[u][v] = 1;//标记u v已经连接
            }
        }
        topu();
    }
    return 0;
}
View Code

强连通分量

每头奶牛都梦想成为牛棚里的明星。被所有奶牛喜欢的奶牛就是一头明星奶牛。所有奶牛都是自恋狂,每头奶牛总是喜欢自己的。奶牛之间的“喜欢”是可以传递的——如果A喜 欢B,B喜欢C,那么A也喜欢C。牛栏里共有N 头奶牛,给定一些奶牛之间的爱慕关系,请你 算出有多少头奶牛可以当明星。

首先,不难发现,如果这所有的牛都存在同一个强联通分量里。那么它们一定互相受欢迎。

那么,我们怎么来找明星呢。

很简单,找出度为00的强联通分量中的点。这样可以保证所有的人都喜欢它,但是它不喜欢任何人,所以说不存在还有人事明星。

此题还有一个特殊情况:

如果有两个点分别满足出度为零的条件,则没有明星,这样无法满足所有的牛喜欢他。

有了上边的解释,题目就不是那么难了,代码如下

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int maxn=1e4+5;
const int maxm=5e4+5;
int to[maxm],nex[maxm],fir[maxn];
int col,num,dfn[maxn],low[maxn],de[maxn],si[maxn];
int tot=0,co[maxn],n,m;
int top,st[maxn];
template<class T> inline void read(T &x)
{
    x=0;
    register char c=getchar();
    register bool f=0;
    while (!isdigit(c)) f ^=c=='-',c=getchar();
    while (isdigit(c)) x=x*10+c-'0',c=getchar();
    if(f)x=-x;
}
template <class T> inline void print(T x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar('0'+x%10);
}
inline void ins(int x,int y)
{
    to[++tot]=y;
    nex[tot]=fir[x];
    fir[x]=tot;
}
void Tarjan(int u)
{
    dfn[u]=low[u]=++num;
    st[++top]=u;
    for(int i=fir[u];i;i=nex[i])
    {
        int v=to[i];
        if(!dfn[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(!co[v])low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        co[u]=++col;
        ++si[col];
        while(st[top]!=u)
        {
            ++si[col];
            co[st[top]]=col;
            --top;
        }
        --top;
    }
}
int main()
{
    int x,y;
    read(n);read(m);
    for(ri i=1;i<=m;i++)
    {
        read(x);read(y);
        ins(y,x);
    }
    for(ri i=1;i<=n;i++)
        if(!dfn[i])Tarjan(i);
    for(ri i=1;i<=n;i++)
        for(ri j=fir[i];j;j=nex[j])
            if(co[i]!=co[to[j]])de[co[to[j]]]++;
    int ans=0,u=0;
    for(ri i=1;i<=col;i++)if(!de[i])ans=si[i],u++;
    if(u==1)print(ans);
     else print(0);
    return 0;
}
View Code

缩点

void Tarjan(int x){
    sta.push(x);
    ins[x]=1;
    dfn[x]=low[x]=++idx;
    for(int i=head[x];i;i=edge[i].nxt){
        int upup=edge[i].to;
        if(!dfn[upup]){
            Tarjan(upup);
            low[x]=min(low[x],low[upup]);
        }
        else if(ins[upup]){
            low[x]=min(low[x],dfn[upup]);
        }
    }
    if(dfn[x]==low[x]){
        tot++;
        while(sta.top()!=x){
            color[sta.top()]=tot;
            sum[tot]+=val[sta.top()];
            ins[sta.top()]=0;
            sta.pop();
        }
        color[sta.top()]=tot;
        sum[tot]+=val[sta.top()];
        ins[sta.top()]=0;
        sta.pop();
    } 
}

SPFA

void SPFA(){
    memset(dis,0x3f,sizeof(dis));
    memset(times,0,sizeof(times));
    memset(Find,false,sizeof(Find));
    times[start]=1;
    dis[start]=0;
    Find[start]=true;
    qu1.push(start);
    while(!qu1.empty()){
        int now=qu1.front();
        for(int i=head[now];i;i=edge[i].nxt){
            int upup=edge[i].to;
            if(dis[now]+edge[i].w<dis[upup]){
                dis[upup]=dis[now]+edge[i].w;
                if(!Find[upup]){
                    qu1.push(upup);
                    Find[upup]=true;
                    times[upup]++;
                    if(times[upup]>n) return;                
                }
            }
        }
        qu1.pop();
        Find[now]=false; 
    }
}
View Code

kruskal

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 10000;
int u[maxn], v[maxn], w[maxn];
int n, m;
int p[maxn], r[maxn];
bool cmp(int i, int j){return w[i] < w[j];}
int find(int x){return p[x] == x? x: p[x] = find(p[x]);}
int Kruskal(){
  for(int i = 1; i <= m; ++i) r[i] = i;
  for(int i = 1; i <= n; ++i) p[i] = i;
  sort(r+1, r+m+1, cmp);
  int k = 0, ans = 0;
  for(int i = 1 ; i <= m; ++i) {
    int e = r[i]; int x = find(u[e]), y = find(v[e]);
    if(x!=y){ ans += w[e]; ++k; p[x] = y;}
    if ( k == n-1 )break;
  }  
  int root = find(1);
  for(int i =1 ;i <=n; ++i) if(find(i)!=root) return -1;
  return ans;
}  
int main(){
  scanf("%d%d", &n, &m);
  for(int i = 1; i <= m; ++i) scanf("%d%d%d", u+i, v+i, w+i);
  printf("%d
", Kruskal());
  return 0;
}  
/*
5 7
1 2 5
1 3 1
1 4 2
1 5 4
2 4 1
3 4 5
3 5 2
(6)
5 7
1 5 6
2 5 7
2 4 7
2 3 9
1 4 5
1 2 4
3 4 2
(17)
View Code

dijkstra堆优化

int n,m,start,dis[maxn],head[maxn],cnt;
bool vis[maxn];
struct node{
    int nxt,weight,to;
}edge[maxm];
struct qnode{
    int dis,id;
    bool operator <(qnode x)const{
        return dis>x.dis;
    }
}; 
priority_queue<qnode> q;
void addedge(int x,int y,int z){
    edge[++cnt].to=y;
    edge[cnt].weight=z;
    edge[cnt].nxt=head[x];
    head[x]=cnt;
}
void Dijkstra(){
    while(!q.empty()){
        start=q.top().id;
        q.pop();
        if(vis[start]) continue;
        vis[start]=true;
        for(int i=head[start];i;i=edge[i].nxt){
            int upup=edge[i].to;
            if(dis[upup]>dis[start]+edge[i].weight){
                dis[upup]=min(dis[upup],edge[i].weight+dis[start]);
                if(!vis[upup]) q.push((qnode){dis[upup],upup});                
            }
        }    
    }
    void Init(){
    scanf("%d%d%d",&n,&m,&start);
    for(int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
    }
    memset(dis,0x3f,sizeof(dis));
    dis[start]=0;
    memset(vis,false,sizeof(vis));
    while(!q.empty()) q.pop();
    q.push((qnode){0,start});    
}
void print(){
    for(int i=1;i<=n;i++)
        printf("%d ",dis[i]);
    puts("");    
}
}
View Code

欧拉筛

bool isPrime[1000001];
//isPrime[i] == 1表示:i是素数
int Prime[1000001], cnt = 0;
//Prime存质数

void GetPrime(int n)//筛到n
{
    memset(isPrime, 1, sizeof(isPrime));
    //以“每个数都是素数”为初始状态,逐个删去
    isPrime[1] = 0;//1不是素数

    for(int i = 2; i <= n; i++)
    {
        if(isPrime[i])//没筛掉 
            Prime[++cnt] = i; //i成为下一个素数

        for(int j = 1; j <= cnt && i*Prime[j] <= n/*不超上限*/; j++) 
        {
            //从Prime[1],即最小质数2开始,逐个枚举已知的质数,并期望Prime[j]是(i*Prime[j])的最小质因数
            //当然,i肯定比Prime[j]大,因为Prime[j]是在i之前得出的
            isPrime[ i*Prime[j] ] = 0;

            if(i % Prime[j] == 0)//i中也含有Prime[j]这个因子
                break; //重要步骤。见原理
        }
    }
}
View Code

快速幂

#include<bits/stdc++.h>
using namespace std;
long long b,a,p,k,ans=1,c;
int main()
{
    scanf("%d%d%d",&b,&p,&k);
    a=b;c=p;
    while(p>0)//快速幂
    {
        if(p%2!=0)
            ans=ans*b%k;//如果p为单数,乘到ans里面去,然后取模
        b=b*b%k;//每次运算都取模
        p=p>>1;    //用位运算除2,可能会快一点
    }
    printf("%d^%d mod %d=%d",a,c,k,ans);//输出
    return 0;
}
View Code

同余方程

求关于x的同余方程 ax≡1(modb) 的最小正整数解。

#include <iostream>  
#include <cstdio> 
using namespace std;
int a,b,x,y,k;
void exgcd(int a,int b)
{
    if(b==0)
    {
        x=1;
        y=0;
        return;
    }
    exgcd(b,a%b);
    k=x;
    x=y;
    y=k-a/b*y;
    return;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>a>>b;
    exgcd(a,b);
    cout<<(x+b)%b;
}
View Code

并查集

接下来M行,每行包含三个整数Zi、Xi、Yi

当Zi=1时,将Xi与Yi所在的集合合并

当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N

#include<bits/stdc++.h>
using namespace std;
int n,m,z[666666],x[666666],y[666666];
int f[666666];
int find(int x)//找爸爸 
{
    if(f[x]==x)
    {
        return x;
    }
    else
    {
        f[x]=find(f[x]);
    }
    return f[x];
}
void work1(int x,int y)//合并
{
    f[find(y)]=find(x);
}
void work2(int x,int y)//查询
{
    if(find(x)==find(y))
    {
        cout<<"Y"<<endl;
    }
    else
    {
        cout<<"N"<<endl;
    }
}
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    ios::sync_with_stdio(false);//关闭同步使cin,cout变快
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>z[i]>>x[i]>>y[i];
        f[i]=i;
    }
    for(int i=1;i<=m;i++)
    {
        if(z[i]==1)
        {
            work1(x[i],y[i]);
        }
        else
        {
            work2(x[i],y[i]);
        }
    }
    return 0;//完结撒花
}
View Code

KMP

如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。

为了减少骗分的情况,接下来还要输出子串的前缀数组next。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
using namespace std;
char a1[2000000],a2[2000000];
int kmp[2000000];
int main()
{
    scanf("%s%s",a1,a2);
    kmp[0]=kmp[1]=0;//前一位,两位失配了,都只可能将第一位作为新的开头
    int len1=strlen(a1),len2=strlen(a2);
    int k;
    k=0;
    for(int i=1;i<len2;i++)//自己匹配自己
    {
        while(k&&a2[i]!=a2[k])k=kmp[k];//找到最长的前后缀重叠长度
        kmp[i+1]=a2[i]==a2[k]?++k:0;//不相等的情况,即无前缀能与后缀重叠,直接赋值位0(注意是给下一位,因为匹配的是下一位适失配的情况)
    }
    k=0;
    for(int i=0;i<len1;i++)
    {
        while(k&&a1[i]!=a2[k])k=kmp[k];//如果不匹配,则将利用kmp数组往回跳
        k+=a1[i]==a2[k]?1:0;//如果相等了,则匹配下一位
        if(k==len2)printf("%d
",i-len2+2);//如果已经全部匹配完毕,则输出初始位置
    }
    for(int i=1;i<=len2;i++)printf("%d ",kmp[i]);//输出f数组
    return 0;
}
View Code

LCA

如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=500000+2;
int n,m,s;
int k=0;
int head[maxn],d[maxn],p[maxn][21];//head数组就是链接表标配了吧?d存的是深度(deep),p[i][j]存的[i]向上走2的j次方那么长的路径
struct node{
    int v,next;
}e[maxn*2];//存树
void add(int u,int v)
{
    e[k].v=v;
    e[k].next=head[u];
    head[u]=k++;
}               //加边函数
void dfs(int u,int fa)
{
    d[u]=d[fa]+1;
    p[u][0]=fa;
    for(int i=1;(1<<i)<=d[u];i++)
        p[u][i]=p[p[u][i-1]][i-1];
    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].v;
        if(v!=fa)
            dfs(v,u);
    }
}                               //首先进行的预处理,将所有点的deep和p的初始值dfs出来
int lca(int a,int b)                                          //非常标准的lca查找
{
    if(d[a]>d[b])
        swap(a,b);           //保证a是在b结点上方,即a的深度小于b的深度
    for(int i=20;i>=0;i--)
        if(d[a]<=d[b]-(1<<i))
            b=p[b][i];             //先把b移到和a同一个深度
    if(a==b)
        return a;                 //特判,如果b上来和就和a一样了,那就可以直接返回答案了
    for(int i=20;i>=0;i--)
    {
        if(p[a][i]==p[b][i])
            continue;
        else
            a=p[a][i],b=p[b][i];           //A和B一起上移
    }
    return p[a][0];               找出最后a值的数字
}
int main()
{
    memset(head,-1,sizeof(head));
    int a,b;
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);
        add(b,a);                      //无向图,要加两次
    }
    dfs(s,0);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        printf("%d
",lca(a,b));
    }
    return 0;
}
View Code

线段树(区间加,区间和)

#include<iostream>
#include<cstdio>
#define MAXN 1000005
#define ll long long
using namespace std;
ll a[MAXN],ans[MAXN<<2],tag[MAXN<<2];
ll ls(ll x) {
    return x<<1;
}
ll rs(ll x) {
    return x<<1|1;
}
void push_up(ll p) {
    ans[p]=ans[ls(p)]+ans[rs(p)];
}
void build(ll p,ll l,ll r) {
    tag[p]=0;
    if(l==r) {
        ans[p]=a[l];
        return ;
    }
    ll mid=(l+r)>>1;
    build(ls(p),l,mid);
    build(rs(p),mid+1,r);
    push_up(p);
}
void f(ll p,ll l,ll r,ll k) {
    tag[p]=tag[p]+k;
    ans[p]=ans[p]+k*(r-l+1);
}
void push_down(ll p,ll l,ll r) {
    ll mid=(l+r)>>1;
    f(ls(p),l,mid,tag[p]);
    f(rs(p),mid+1,r,tag[p]);
    tag[p]=0;
}
void update(ll nl,ll nr,ll l,ll r,ll p,ll k) {
    if(nl<=l&&r<=nr) {
        ans[p]+=k*(r-l+1);
        tag[p]+=k;
        return ;
    }
    push_down(p,l,r);
    ll mid=(l+r)>>1;
    if(nl<=mid)update(nl,nr,l,mid,ls(p),k);
    if(nr>mid) update(nl,nr,mid+1,r,rs(p),k);
    push_up(p);
}
ll query(ll q_x,ll q_y,ll l,ll r,ll p) {
    ll res=0;
    if(q_x<=l&&r<=q_y)return ans[p];
    ll mid=(l+r)>>1;
    push_down(p,l,r);
    if(q_x<=mid)res+=query(q_x,q_y,l,mid,ls(p));
    if(q_y>mid) res+=query(q_x,q_y,mid+1,r,rs(p));
    return res;
}
int main() {
    ll a1,b,c,d,e,f,n,m;
    scanf("%lld%lld",&n,&m);
    for(ll i=1; i<=n; i++)
        scanf("%lld",&a[i]);
    build(1,1,n);
    while(m--) {
        scanf("%lld",&a1);
        switch(a1) {
            case 1: {
                scanf("%lld%lld%lld",&b,&c,&d);
                update(b,c,1,n,1,d);
                break;
            }
            case 2: {
                scanf("%lld%lld",&e,&f);
                printf("%lld
",query(e,f,1,n,1));
                break;
            }
        }
    }
    return 0;
}
View Code

网络流(EK,Dinic,ISAP)

#include <cstdio>
#include <memory.h>
#include <queue>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define MAXN 10000
#define MAXM 100000
#define INF (1<<30)
namespace G{
    /*
    本例中使用前向星存图
    注意它与普通前向星的区别:
    普通前向星编号从1开始,而这里从0开始
    这样可以确保第i条边的反向弧就是第i^1条边
    */
    int n,m,S,T;
    struct Edge{
        int from,to,cap,nxt;
    }e[MAXM*2+10];
    int head[MAXN+10],cur[MAXN+10],cnt;
    inline void Init(){     //初始化,准备建图
        memset(head,-1,sizeof(head));
        cnt=-1;
    }
    inline void AddEdge(int u,int v,int w){     //添加一条边及其反向弧
        e[++cnt]=(Edge){u,v,w,head[u]};     //加入这条边
        head[u]=cnt;
        e[++cnt]=(Edge){v,u,0,head[v]};     //加入它的反向弧
        head[v]=cnt;
    }
    //以下为Dinic
    int dep[MAXN+10];       //记录每个点的编号
    bool Dinic_BFS(){
        std::queue<int> q;
        memset(dep,0,sizeof(dep));
        dep[S]=1;
        q.push(S);
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=head[x];~i;i=e[i].nxt)
                if(e[i].cap>0 && dep[e[i].to]==0){
                    dep[e[i].to]=dep[x]+1;
                    q.push(e[i].to);
                }
        }
        return dep[T];
    }
    int Dinic_DFS(int u,int now){
        if(u==T)
            return now;
        int ret=0;
        for(int &i=cur[u];~i;i=e[i].nxt)        //当前弧优化
            if(dep[e[i].to]==dep[u]+1 && e[i].cap){
                int di=Dinic_DFS(e[i].to,min(e[i].cap,now-ret));        //向下搜索
                if(di){     //增广
                    e[i].cap-=di;
                    e[i^1].cap+=di;
                    ret+=di;
                    if(ret==now)
                        break;
                }
            }
        return ret;
    }
    inline int Dinic(){
        int ret=0;
        while(Dinic_BFS()){     //BFS分层
            memcpy(cur,head,sizeof(head));      //当前弧优化
            ret+=Dinic_DFS(S,INF);      //DFS找增广路
        }
        return ret;
    }
    //以下为EK
    bool vis[MAXN+10];      //记录每个点是否经过
    int pre[MAXN+10];       //记录增广路
    int EK_BFS(){
        memset(pre,-1,sizeof(pre));
        memset(vis,false,sizeof(vis));
        std::queue<int> q;
        q.push(S);
        vis[S]=true;
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=head[x];~i;i=e[i].nxt)
                if(e[i].cap>0 && !vis[e[i].to]){
                    pre[e[i].to]=i;
                    vis[e[i].to]=true;
                    if(e[i].to==T)
                        return true;
                    q.push(e[i].to);
                }
        }
        return false;
    }
    inline int EK(){
        int ret=0;
        while(EK_BFS()){        //BFS找增广路
            int di=INF;
            for(int i=pre[T];~i;i=pre[e[i].from])       //找到这条路上容量最小的边
                di=min(di,e[i].cap);
            for(int i=pre[T];~i;i=pre[e[i].from]){      //增广
                e[i].cap-=di;
                e[i^1].cap+=di;
            }
            ret+=di;
        }
        return ret;
    }
    //以下为ISAP
    int gap[MAXN+10];       //GAP优化:当某一层没有任何点时停止算法
    void ISAP_BFS(){        //BFS初始化
        memset(dep,-1,sizeof(dep));
        memset(gap,0,sizeof(gap));
        dep[T]=0; gap[1]=1;
        std::queue<int> q;
        q.push(T);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=head[u];~i;i=e[i].nxt){
                if(dep[e[i].to]!=-1)
                    continue;
                q.push(e[i].to);
                dep[e[i].to]=dep[u]+1;
                gap[dep[e[i].to]]++;        //更新GAP数组
            }
        }
        return;
    }
    int ISAP_DFS(int u,int flow){       //DFS增广,原理类似Dinic,不解释
        if(u==T)
            return flow;
        int ret=0;
        for(int &i=cur[u];~i;i=e[i].nxt){
            if(e[i].cap && dep[e[i].to]+1==dep[u]){
                int di=ISAP_DFS(e[i].to,min(e[i].cap,flow-ret));
                if(di){
                    e[i].cap-=di;
                    e[i^1].cap+=di;
                    ret+=di;
                }
                if(ret==flow)
                    return ret;
            }
        }
        gap[dep[u]]--;
        if(gap[dep[u]]==0)      //GAP优化
            dep[S]=n+1;
        dep[u]++;
        gap[dep[u]]++;
        return ret;
    }
    int ISAP(){
        ISAP_BFS();
        int ret=0;
        while(dep[S]<=n){
            memcpy(cur,head,sizeof(head));      //当前弧优化
            ret+=ISAP_DFS(S,INF);
        }
        return ret;
    }
}
int main(){     //主程序,不解释
    scanf("%d%d%d%d",&G::n,&G::m,&G::S,&G::T);
    G::Init();
    for(int i=1;i<=G::m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        G::AddEdge(u,v,w);
    }
    //printf("%d
",G::Dinic());
    // printf("%d
",G::EK());
    printf("%d
",G::ISAP());
    return 0;
}
View Code

 网络流(ISAP)优版

#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define LL long long
#define MAXN 100000+5

using namespace std;

inline int read()
{
  char ch=getchar();int x=0,f=1;
  while (ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x*f;
}

struct Node
{
  int v,next,w;
};

Node node[(MAXN)<<1];
int dis[10001],gap[10001];
int p[10001],pp[10001];
int cnt=-1;
int s,t,n,m;
bool used[10001];
queue<int> q;

void addedge(int u,int v,int w)
{
  node[++cnt].v=v;
  node[cnt].next=p[u];
  node[cnt].w=w;
  p[u]=cnt;
}

void bfs(int o)
{
  q.push(o);
  dis[o]=0;
  used[o]=1;
  while(!q.empty())
  {
    int head=q.front();
    gap[dis[head]]++;
    for(int i=p[head];~i;i=node[i].next)
      if(node[i^1].w&&!used[node[i].v])
      {
        dis[node[i].v]=dis[head]+1;
        used[node[i].v]=1;
        q.push(node[i].v);
      }
    q.pop();
  }
}

int flow(int o,int flows)
{
  if(o==t) return flows;
  int sum=0;
  for(int i=p[o];~i;i=node[i].next)
  if(node[i].w&&dis[node[i].v]==dis[o]-1)
  {
    int f=flow(node[i].v,min(flows-sum,node[i].w));
    node[i].w-=f;node[i^1].w+=f;
    sum+=f;p[o]=i;
    if (sum==flows||dis[s]==n) return sum;
  }
  if (!--gap[dis[o]++]) dis[s]=n;
  ++gap[dis[o]];p[o]=pp[o];
  return sum;
}

int main()
{
  n=read(),m=read(),s=read(),t=read();
  memset(p,-1,sizeof(p));
  for(int i=1;i<=m;i++)
  {
    int u=read(),v=read(),w=read();
    addedge(u,v,w);
    addedge(v,u,0);
  }
  memcpy(pp,p,sizeof(p));
  bfs(t);
  long long ans=0;
  while(dis[s]<n)
    ans+=(LL)(flow(s,0x7fffffff));
  printf("%lld
",ans);
  return 0;
}
View Code

FFT(高精乘)

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <complex>
#define space putchar(' ')
#define enter putchar('
')
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
    if(c == '-') op = 1;
        x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
const int N = 1000005;
const double PI = acos(-1);
typedef complex <double> cp;
char sa[N], sb[N];
int n = 1, lena, lenb, res[N];
cp a[N], b[N], omg[N], inv[N];
void init(){
    for(int i = 0; i < n; i++){
        omg[i] = cp(cos(2 * PI * i / n), sin(2 * PI * i / n));
        inv[i] = conj(omg[i]);
    }
}
void fft(cp *a, cp *omg){
    int lim = 0;
    while((1 << lim) < n) lim++;
    for(int i = 0; i < n; i++){
        int t = 0;
        for(int j = 0; j < lim; j++)
            if((i >> j) & 1) t |= (1 << (lim - j - 1));
        if(i < t) swap(a[i], a[t]); // i < t 的限制使得每对点只被交换一次(否则交换两次相当于没交换)
    }
    for(int l = 2; l <= n; l *= 2){
        int m = l / 2;
    for(cp *p = a; p != a + n; p += l)
        for(int i = 0; i < m; i++){
            cp t = omg[n / l * i] * p[i + m];
            p[i + m] = p[i] - t;
            p[i] += t;
        }
    }
}
int main(){
    scanf("%s%s", sa, sb);
    lena = strlen(sa), lenb = strlen(sb);
    while(n < lena + lenb) n *= 2;
    for(int i = 0; i < lena; i++)
        a[i].real(sa[lena - 1 - i] - '0');
    for(int i = 0; i < lenb; i++)
        b[i].real(sb[lenb - 1 - i] - '0');
    init();
    fft(a, omg);
    fft(b, omg);
    for(int i = 0; i < n; i++)
        a[i] *= b[i];
    fft(a, inv);
    for(int i = 0; i < n; i++){
        res[i] += floor(a[i].real() / n + 0.5);
        res[i + 1] += res[i] / 10;
        res[i] %= 10;
    }
    for(int i = res[lena + lenb - 1] ? lena + lenb - 1: lena + lenb - 2; i >= 0; i--)
        putchar('0' + res[i]);
    enter;
    return 0;
}
View Code

FFT(多项式乘法)

#include <cmath>
#include <cstdio>
#include <iostream>
#define il inline
using namespace std ;
int N, M, K ;
const int MAXN = 3000100 ;
const double Pi = acos(-1.0) ;
int i, j, k, l, Lim = 1, L, R[MAXN] ; 
struct node{
    double x, y ;
    node (double xx = 0, double yy = 0){
        x = xx, y = yy ;
    }
}A[MAXN], B[MAXN] ;
node operator * (node J, node Q){
    return node(J.x * Q.x - J.y * Q.y , J.x * Q.y + J.y * Q.x);
}
node operator + (node J, node Q){
    return node(J.x + Q.x , J.y + Q.y);
}
node operator - (node J, node Q){
    return node(J.x - Q.x , J.y - Q.y );
}

il int qr(){
    int k = 0, f = 1 ;
    char c = getchar() ;
    while(!isdigit(c)){if(c == '-') f = -1 ;c = getchar() ;}
    while(isdigit(c)) k = (k << 1) + (k << 3) + c - 48 ,c = getchar() ;
    return k * f ;
}
void FFT(node *J, int flag){
    for(i = 0; i < Lim; i ++)
        if(i < R[i]) swap(J[i], J[R[i]]) ;
    for(j = 1; j < Lim; j <<= 1){
        node T(cos(Pi / j), flag * sin(Pi / j)) ;
        for(k = 0; k < Lim; k += (j << 1) ){
            node t(1, 0) ;
            for(l = 0 ; l < j; l ++, t = t * T){
                node Nx = J[k + l], Ny = t * J[k + j + l] ;
                J[k + l] = Nx + Ny ;
                J[k + j + l] = Nx - Ny ;
            }
        }
    }
}
int main(){
    N = qr(), M = qr() ; 
    for(i = 0; i <= N; i ++) A[i].x = qr() ;
    for(i = 0; i <= M; i ++) B[i].x = qr() ;
    while(Lim <= N + M) Lim <<= 1, L ++ ;
    for(i = 0; i < Lim; i ++ ) R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1)) ;
    FFT(A, 1), FFT(B, 1) ;
    for(i = 0; i <= Lim; i ++) A[i] = A[i] * B[i] ;
    FFT(A, -1) ;
    for(i = 0; i <= N + M; i ++)
        printf("%d ", (int)(A[i].x / Lim + 0.5)) ;
    puts("");
    return 0 ;
}
View Code

char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?EOF:*p1++)inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();return x*f;}

原文地址:https://www.cnblogs.com/zzrblogs/p/10547541.html