• 模板


    快读

    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;}

  • 相关阅读:
    OnClick方法与Click事件
    词法,语法,语义
    静态成员与实例成员
    依赖属性 DependencyProperty
    依赖,关联,聚合,合成
    数据可视化
    ref 与out
    理解TCP为什么需要进行三次握手(白话)
    禁止访问网站中所有的动态页面
    linux 重命名文件和文件夹
  • 原文地址:https://www.cnblogs.com/zzrblogs/p/10547541.html
Copyright © 2020-2023  润新知