积累一些题

luogu p2472

直接最大流,拆点限制经过次数即可

#include <bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=r;i>=l;--i)
using namespace std;
typedef long long s64;
 
 
const int M=2e3+5;
 
int n,m,d;
char s[25];
int a[25][25];
int S,T,dep[M],e_size,head[M];
 
 
struct edge {
    int v,w,nxt;
}e[M*10];
 
void e_add(int u,int v,int w) {
    e[++e_size]=(edge){v,w,head[u]};
    head[u]=e_size;
}
 
 
bool Bfs() {
    queue <int> q;
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    q.push(S);
    while (!q.empty()) {
        int r=q.front();
        q.pop();
        for(int i=head[r];i;i=e[i].nxt) {
            int v=e[i].v;
            if(!dep[v]&&e[i].w) {
                dep[v]=dep[r]+1;
                q.push(v);
                if(v==T) return 1;
            }
        }
    }
    return 0;
}
 
int Dfs(int x,int cp) {
    if(x==T) return cp;
    int las=cp,q;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dep[v]==dep[x]+1&&e[i].w&&las) {
            q=Dfs(v,min(las,e[i].w));
            if(!q) {dep[v]=0;continue;}
            e[i].w-=q,las-=q,e[i^1].w+=q;
            if(!las) break;
        }
    }
    return cp-las;
}
 
int main() {
    //freopen("a.in","r",stdin);
 
    scanf("%d%d%d",&n,&m,&d);
    rep(i,1,n) {
        scanf("%s",s+1);
        rep(j,1,m) a[i][j]=s[j]-'0';
    }
 
    S=M-2,T=M-1;
    int ans=0;
 
    e_size=1;
    rep(i,1,n) {
        scanf("%s",s+1);
        rep(j,1,m) if(s[j]=='L') {
            ++ans;
            int x=S,y=i*m-m+j;
            e_add(x,y,1),e_add(y,x,0);
        }
    }
 
    rep(i,1,n) rep(j,1,m) if(a[i][j]) {
        int x=i*m-m+j,y=x+n*m;
        e_add(x,y,a[i][j]),e_add(y,x,0);
    }
 
    rep(i,1,n) rep(j,1,m) if(a[i][j]) {
        bool vis=0;
        int u=i*m-m+j+n*m;
        rep(x,i-d,i+d) rep(y,j-d,j+d) {
            if((x-i)*(x-i)+(y-j)*(y-j)>d*d) continue;
            if(x<1||y<1||x>n||y>m) {
                if(!vis) vis=1,e_add(u,T,1e5),e_add(T,u,0);
            }
            else if(a[x][y]) {
                int v=x*m-m+y;
                //cout<<u<<" "<<v<<endl;
                e_add(u,v,1e5),e_add(v,u,0);
            }
        }
    }
    
    while (Bfs()) ans-=Dfs(S,1e5);
 
    cout<<ans<<endl;
}
bzoj 1066

 

luogu p3305

显然二分+最大流 

#include <bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=r;i>=l;--i)
using namespace std;
typedef long long s64;
 
const int M=1e3+5;
const double eps=1e-10;
 
int n,m;
double p,a[M*10];
int e_size,head[M],dep[M];
 
struct edge {
    int v;
    double w;
    int nxt;
}e[M*10];
 
void e_add(int u,int v,double w) {
    e[++e_size]=(edge) {v,w,head[u]};
    head[u]=e_size;
    a[e_size]=w;
}
 
 
bool Bfs() {
    queue <int> q;
    memset(dep,0,sizeof(dep));
    dep[1]=1;
    q.push(1);
    while (!q.empty()) {
        int r=q.front();
        q.pop();
        for(int i=head[r];i;i=e[i].nxt) {
            int v=e[i].v;
            if(!dep[v]&&e[i].w>eps) {
                dep[v]=dep[r]+1;
                q.push(v);
                if(v==n) return 1;
            }
        }
    }
    return 0;
}
 
double Dfs(int x,double cp) {
    if(x==n) return cp;
    double las=cp,q;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dep[v]==dep[x]+1&&e[i].w>eps&&las>eps) {
            q=Dfs(v,min(las,e[i].w));
            if(q<eps) {dep[v]=0;continue;}
            e[i].w-=q,las-=q,e[i^1].w+=q;
        }
    }
    return cp-las;
}
 
 
double calc(double Min) {
    rep(i,2,e_size) e[i].w=min(Min,a[i]);
 
    double ans=0;
    while (Bfs()) ans+=Dfs(1,1e9);
    return ans;
}
 
int main() {
    //freopen("a.in","r",stdin);
    scanf("%d%d%lf",&n,&m,&p);
    e_size=1;
    rep(i,1,m) {
        int x,y;
        double c;
        scanf("%d%d%lf",&x,&y,&c);
        e_add(x,y,c),e_add(y,x,0);
    }
 
    double ans=0;
    while (Bfs()) ans+=Dfs(1,1e9);
    printf("%.0f\n",ans);
 
    double l=0,r=5e4,mid;
    while (l+eps<r) {
        mid=(l+r)/2;
        if(calc(mid)+eps>ans) r=mid;
        else l=mid;
    }
    printf("%.4f\n",r*p);
}
bzoj 3130

 

luogu p5038

偶数想出来了,显然可以二分,然后直接黑白染色就行了

奇数可以直接解出答案check。。。

#include <bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=r;i>=l;--i)
using namespace std;
typedef long long s64;

const int M=3e3+5;
int n,m;
int S,T,a[55][55];
int e_size,head[M],dep[M];
int x_[4]={0,0,-1,1},y_[4]={1,-1,0,0};

struct edge {
    int u,v;
    s64 w;
    int nxt;
}e[M*10];

void e_add(int u,int v,s64 w) {
    e[++e_size]=(edge){u,v,w,head[u]};
    head[u]=e_size;
}


bool Bfs() {
    queue <int> q;
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    q.push(S);

    while (!q.empty()) {
        int r=q.front();
        q.pop();
        for(int i=head[r];i;i=e[i].nxt) {
            int v=e[i].v;
            if(!dep[v]&&e[i].w) {
                dep[v]=dep[r]+1;
                q.push(v);
                if(v==T) return 1;
            }
        }
    }
    return 0;
}

s64 Dfs(int x,s64 cp) {
    if(x==T) return cp;
    s64 las=cp,q;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dep[v]==dep[x]+1&&e[i].w&&las) {
            q=Dfs(v,min(e[i].w,las));
            if(!q) {dep[v]=0;continue;}
            e[i].w-=q,e[i^1].w+=q,las-=q;
        }
    }
    return cp-las;
}

bool check(s64 val) {
    e_size=1;
    memset(head,0,sizeof(head));
    s64 tot=0;
    rep(i,1,n) rep(j,1,m) {
        int x=i*m-m+j;
        tot+=val-a[i][j];
        if(i+j&1) e_add(S,x,val-a[i][j]),e_add(x,S,0);
        else      e_add(x,T,val-a[i][j]),e_add(T,x,0);
    }

    rep(i,1,n) rep(j,1,m) if(i+j&1) rep(k,0,3) {
        int x=i+x_[k],y=j+y_[k];
        int u=i*m-m+j,v=x*m-m+y;
        if(!(x<1||y<1||x>n||y>m)) e_add(u,v,1e18),e_add(v,u,0);
    }

    s64 sum=0;
    while (Bfs()) sum+=Dfs(S,1e18);
    return sum==tot/2;
}

int main() {
    //freopen("a.in","r",stdin);
    int test_;
    scanf("%d",&test_);
    while (test_--) {
        S=M-2,T=S+1;

        int mx=0;
        s64 cnt[2]={0};
        s64 sum[2]={0};
        scanf("%d%d",&n,&m);
        rep(i,1,n) rep(j,1,m) {
            scanf("%d",a[i]+j);
            mx=max(mx,a[i][j]);
            ++cnt[i+j&1],sum[i+j&1]+=a[i][j];
        }

        if(cnt[0]!=cnt[1]) {
            s64 ans=(sum[0]-sum[1])/(cnt[0]-cnt[1]);
            if(ans<mx||!check(ans)) puts("-1");
            else printf("%lld\n",ans*n*m-sum[0]-sum[1]>>1);
        }
        else {
            if(sum[0]!=sum[1]) puts("-1");
            else {
                s64 l=mx,r=1e16,mid,ans=-1;
                while (l<=r) {
                    mid=l+r>>1;
                    if(check(mid)) ans=mid,r=mid-1;
                    else l=mid+1;
                }
                if(ans==-1) puts("-1");
                else printf("%lld\n",ans*n*m-sum[0]-sum[1]>>1);
            }
        }
    }
}
bzoj 2756

 

luogu p4542

一个裸的上下界可行流

注意最短路用floyd保证经过的点都小于等于k

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;

const int M=3e2+10;

int n,m,K;
int S,T,a[M][M];
int dis[M],inq_[M],pre[M];
int e_size,head[M];

struct edge{
    int u,v,w,c,nxt;
}e[M*M*10];

void e_add(int u,int v,int w,int c) {
    e[++e_size]=(edge){u,v,w,c,head[u]};
    head[u]=e_size;
}


void insert(int u,int v,int w,int c) {
    e_add(u,v,w,c),e_add(v,u,0,-c);
}

void spfa() {
    queue <int> q;
    memset(inq_,0,sizeof(inq_));
    memset(dis,0x7f,sizeof(dis));
    
    dis[S]=0;
    q.push(S);
    while (!q.empty()) {
        int r=q.front();
        q.pop();
        inq_[r]=0;
        for(int i=head[r];i;i=e[i].nxt) {
            int v=e[i].v;
            if(e[i].w&&dis[v]>dis[r]+e[i].c) {
                pre[v]=i;
                dis[v]=dis[r]+e[i].c;
                if(!inq_[v]) q.push(v),inq_[v]=1;
            }
        }
    }
}

int feiyong() {
    int ans=0;
    while (spfa(),dis[T]<2e9) {
        int t=2e9;
        for(int i=pre[T];i;i=pre[e[i].u]) t=min(t,e[i].w);
        //cout<<t<<endl;
        ans+=t*dis[T];
        for(int i=pre[T];i;i=pre[e[i].u]) e[i].w-=t,e[i^1].w+=t;
    }
    return ans;
}

int main() {
    //freopen("a.txt","r",stdin);
    scanf("%d%d%d",&n,&m,&K);
    
    ++n;
    memset(a,0x3f,sizeof(a));
    rep(i,1,n) a[i][i]=0;
    rep(i,1,m) {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        ++x,++y;
        if(z<a[x][y]) a[x][y]=a[y][x]=z;
    }
    
    
    
    
    e_size=1;
    rep(u,1,n) {
        rep(i,1,n) rep(j,1,n) a[i][j]=min(a[i][j],a[i][u]+a[u][j]);
        if(u>1) insert(2*n+3,u,1e9,a[1][u]);
        rep(i,2,u-1) insert(i+n,u,1e9,a[i][u]);
    }
    insert(n+1,1,1e9,0);
    insert(1,2*n+3,K,0);
    rep(i,2,n) {
        insert(i,i+n,1e9,0);
        insert(i+n,n+1,1e9,0);
    }
    
    
    S=2*n+1,T=S+1;
    rep(i,2,n) insert(S,i+n,1,0),insert(i,T,1,0);
    
    printf("%d\n",feiyong());
}
luogu 4542

 

 

luogu p2805

tarjan去掉不可能吃的plants之后裸的最大权闭合子图

#include <bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;


const int M=1e5+5;

int n,m;
int a[55][55];
bool not_[M];
int be[M],dfn[M],low[M],time_,size[M];
int S,T,e_size,head[M],dep[M];

stack <int> sta;

vector <int> to[M];

struct edge {
    int v,w,nxt;
}e[M*10];

void e_add(int u,int v,int w) {
    e[++e_size]=(edge){v,w,head[u]};
    head[u]=e_size;
}

void insert(int u,int v,int w) {
    e_add(u,v,w),e_add(v,u,0);
}


void tarjan(int x) {
    dfn[x]=low[x]=++time_;
    sta.push(x);
    
    for(auto v:to[x]) {
        if(!dfn[v]) {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(!be[v]) low[x]=min(low[x],dfn[v]);
    }
    
    if(low[x]==dfn[x]) {
        be[0]++;
        while(1) {
            ++size[be[0]];
            int t=sta.top();
            sta.pop();
            be[t]=be[0];
            if(x==t) break;
        }
    }
}



bool Bfs() {
    queue <int> q;
    memset(dep,0,sizeof(dep));
    q.push(S);
    dep[S]=1;
    while (!q.empty()) {
        int r=q.front();
        q.pop();
        for(int i=head[r];i;i=e[i].nxt) {
            int v=e[i].v;
            if(!dep[v]&&e[i].w) {
                dep[v]=dep[r]+1;
                q.push(v);
                if(v==T) return 1;
            }
        }
    }
    return 0;
}

int Dfs(int x,int cp) {
    if(x==T) return cp;
    int las=cp,q;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dep[v]==dep[x]+1&&las&&e[i].w) {
            q=Dfs(v,min(e[i].w,las));
            if(!q) {dep[v]=0;continue;}
            las-=q,e[i].w-=q,e[i^1].w+=q;
        }
    }
    return cp-las;
}

int main() {
    //freopen("a.txt","r",stdin);
    
    scanf("%d%d",&n,&m);
    rep(i,1,n) rep(j,1,m) {
        scanf("%d",a[i]+j);
        int cnt,x,y;
        scanf("%d",&cnt);
        rep(k,1,cnt) {
            scanf("%d%d",&x,&y);
            ++x,++y;
            to[i*m-m+j].push_back(x*m-m+y);
        }
        if(j>1) to[i*m-m+j].push_back(i*m-m+j-1);
    }
    
    rep(i,1,n*m) if(!dfn[i]) tarjan(i);
    rep(i,1,n*m) if(size[be[i]]>1) not_[i]=1;
    rep(i,1,n*m) per(j,m-1,1) if(not_[i*m-m+j+1]) not_[i*m-m+j]=1;
    
    
    e_size=1;
    int ans=0;
    S=n*m+1,T=S+1;
    rep(i,1,n) rep(j,1,m) {
        int x=i*m-m+j;
        if(not_[x]) continue;
        for(auto v:to[x]) if(!not_[v]) insert(v,x,1e9);
        ans+=max(0,a[i][j]);
        if(a[i][j]>0) insert(S,x,a[i][j]);
        else          insert(x,T,-a[i][j]);
    }
    
    while (Bfs()) ans-=Dfs(S,1e9);
    cout<<ans<<endl;
    
    return 0;
}
luogu p2805

 

luogu p3749

裸的最大权闭合子图

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;


const int M=1e2+5;
const int N=1e4+5;
const int inf=0x7fffffff;

int n,m;
int S,T;
int a[M],b[M][M],id[M][M];
int e_size,dep[N],head[N];


struct edge{
    int v,w,nxt;
}e[N*10];

void e_add(int u,int v,int w) {
    e[++e_size]=(edge){v,w,head[u]};
    head[u]=e_size;
}

void insert(int u,int v,int w) {
    e_add(u,v,w),e_add(v,u,0);
}

bool Bfs() {
    queue <int> q;
    memset(dep,0,sizeof(dep));

    dep[S]=1;
    q.push(S);
    while (!q.empty()) {
        int r=q.front();
        q.pop();
        for(int i=head[r];i;i=e[i].nxt) {
            int v=e[i].v;
            if(!dep[v]&&e[i].w) {
                dep[v]=dep[r]+1;
                q.push(v);
                if(v==T) return 1;
            }
        }
    }
    return 0;
}

int Dfs(int x,int cp) {
    if(x==T) return cp;
    int las=cp,q;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dep[v]==dep[x]+1&&e[i].w&&las) {
            q=Dfs(v,min(e[i].w,las));
            if(!q) {dep[v]=0;continue;}
            las-=q,e[i].w-=q,e[i^1].w+=q;
        }
    }
    return cp-las;
}

int main() {
    //freopen("a.txt","r",stdin);
    //printf("%d\n",inf);
    scanf("%d%d",&n,&m);
    rep(i,1,n) scanf("%d",a+i);
    rep(i,1,n) rep(j,i,n) scanf("%d",b[i]+j),id[i][j]=++id[0][0];
    rep(i,1,n) b[i][i]-=a[i];

    int ans=0;
    e_size=1;
    S=id[n][n]+1001,T=S+1;
    rep(i,1,n) rep(j,i,n) {
        ans+=max(0,b[i][j]);
        if(i==j) {
            insert(id[i][j],a[i]+id[n][n],inf);
            b[i][j]>0?insert(S,id[i][j],b[i][j]):insert(id[i][j],T,-b[i][j]);
        }
        else {
            insert(id[i][j],id[i][j-1],inf);
            insert(id[i][j],id[i+1][j],inf);
            b[i][j]>0?insert(S,id[i][j],b[i][j]):insert(id[i][j],T,-b[i][j]);
        }
    }

    sort(a+1,a+n+1);
    a[0]=a[1]-1;
    rep(i,1,n) if(a[i]!=a[i-1]) insert(id[n][n]+a[i],T,m*a[i]*a[i]);


    while(Bfs()) ans-=Dfs(S,inf);
    printf("%d\n",ans);
}
bzoj 4873

 

luogu p4126

需要仔细想一下条件

可能在:u,v不在一个scc内(即所有条件下都满流)

必须在:S和u在一个scc内,v和T在一个scc内(若不删这条边就可以增广)

#include <queue>
#include <stack>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;


const int M=4e3+5;
const int N=6e4+5;
const int inf=0x7fffffff;

int n,m,S,T;
int dep[M],e_size,head[M];
int be[M],low[M],dfn[M],time_;
stack <int> sta;

struct edge{
    int u,v,w,nxt;
}e[N*10];

void e_add(int u,int v,int w) {
    e[++e_size]=(edge){u,v,w,head[u]};
    head[u]=e_size;
}

bool Bfs() {
    queue <int> q;
    memset(dep,0,sizeof(dep));

    dep[S]=1;
    q.push(S);
    while (!q.empty()) {
        int r=q.front();
        q.pop();
        for(int i=head[r];i;i=e[i].nxt) {
            int v=e[i].v;
            if(!dep[v]&&e[i].w) {
                dep[v]=dep[r]+1;
                q.push(v);
                if(v==T) return 1;
            }
        }
    }
    return 0;
}

int Dfs(int x,int cp) {
    if(x==T) return cp;
    int las=cp,q;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dep[v]==dep[x]+1&&e[i].w&&las) {
            q=Dfs(v,min(e[i].w,las));
            if(!q) {dep[v]=0;continue;}
            las-=q,e[i].w-=q,e[i^1].w+=q;
        }
    }
    return cp-las;
}


void tarjan(int x) {
    low[x]=dfn[x]=++time_;
    sta.push(x);

    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(!e[i].w) continue;
        if(!dfn[v]) {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(!be[v]) low[x]=min(low[x],dfn[v]);
    }

    
    if(low[x]==dfn[x]) {
        ++be[0];
        while(1) {
            int tmp=sta.top();
            sta.pop();
            be[tmp]=be[0];
            if(x==tmp) break;
        }
    }
}

int main() {
    //freopen("a.txt","r",stdin);
    scanf("%d%d%d%d",&n,&m,&S,&T);
    e_size=1;
    rep(i,1,m) {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        e_add(u,v,w),e_add(v,u,0);
    }

    while (Bfs()) Dfs(S,inf);

    rep(i,1,n) if(!dfn[i]) tarjan(i);//脑残吗

    for(int i=2;i<=e_size;i+=2) {
        if(e[i].w) puts("0 0");
        else {
            be[e[i].u]==be[e[i].v]?printf("0 "):printf("1 ");
            be[e[i].u]==be[S]&&be[e[i].v]==be[T]?puts("1"):puts("0");
        }
    }
}
bzoj 1797

 

bzoj 3281

边转化为点用支配树求出必经边

因为必经点所以$dis[nxt]-dis[pre]$就是最短路径

得到数列单调指针覆盖即可

注意脑子不清醒写的代码一定要重写

#include <set>
#include <stack>
#include <ctime>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define fir first
#define sec second
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(l);i>=(r);--i)
using namespace std;
typedef long long s64;
 
 
const int M=5e5+5;
int n,m,S,T,len;
int head[M],e_size,dis[M];
int st[M],id[M],sdom[M],idom[M];
int be[M],f[M],fa[M],sta[M],g[M];
 
 
bool vis[M];
 
vector <int> to[M],pre[M],buc[M];
 
struct edge{
    int u,v,w,nxt;
}e[M*5];
 
void e_add(int u,int v,int w) {
    e[++e_size]=(edge){u,v,w,head[u]};
    head[u]=e_size;
}
 
 
void dijkstra() {
    rep(i,1,n) dis[i]=2147483647;
    dis[S]=0;
    set <pair<int,int> > q;
    q.insert(make_pair(0,S));
    int cnt=0;
    while (!q.empty()) {
        ++cnt;
        pair<int,int> r=*q.begin();
        q.erase(q.begin());
        if(dis[r.sec]!=r.fir) continue;
        for(int i=head[r.sec];i;i=e[i].nxt) {
            int v=e[i].v;
            if(dis[v]>dis[r.sec]+e[i].w) {
                dis[v]=dis[r.sec]+e[i].w;
                q.insert(make_pair(dis[v],v));
            }
        }
    }
}
 
void dfs(int x) {
    id[x]=++id[0];
    st[id[0]]=x;
 
    be[x]=x;
    f[x]=x;
    sdom[x]=id[x];//
 
    for(int v,i=to[x].size()-1;i>=0;--i) {
        v=to[x][i];
        if(!id[v]) fa[v]=x,dfs(v);
    }
}
 
int find(int x) {
    if(x==be[x]) return f[x];
    int now=find(be[x]);
    be[x]=be[be[x]];
    if(sdom[now]<sdom[f[x]]) f[x]=now;
    return f[x];
}
 
void make_dominator_tree() {
    rep(i,1,m) {
        int u=e[i].u,v=e[i].v;
         
        to[u].push_back(n+i);
        to[n+i].push_back(v);
 
        pre[n+i].push_back(u);
        pre[v].push_back(n+i);
    }
 
    dfs(S);
 
    per(i,id[0],2) {
        int p=st[i];
        for(int i=pre[p].size()-1;i>=0;--i) {
            int v=pre[p][i];
            if(id[v]) sdom[p]=min(sdom[p],sdom[find(v)]);
        }
        be[p]=fa[p];
 
 
        buc[st[sdom[p]]].push_back(p);
 
        for(int i=buc[fa[p]].size()-1;i>=0;--i) {
            int v=buc[fa[p]][i];
            int u=find(v);
 
            if(sdom[u]==sdom[v]) vis[v]=1,idom[v]=sdom[v];
            else idom[v]=u;
        }
    }
    rep(i,2,id[0]) if(!vis[st[i]]) idom[st[i]]=idom[idom[st[i]]];//vis[st[i]]啊
}
 
 
void get_ans() {
    int cnt=0;
    int pre=-1,now=st[idom[T]];
    while (now&&now<=n) now=st[idom[now]];
 
    while (now) {
        if(pre!=-1) {
            sta[++cnt]=dis[e[pre-n].u]-dis[e[now-n].v];
        }
        sta[++cnt]=e[now-n].w;
 
 
        pre=now;
        now=st[idom[now]];
        while (now&&now<=n) now=st[idom[now]];
    }
 
    int tot=0;
    rep(i,1,cnt+1>>1) tot+=sta[2*i-1];
    int ans=tot;
 
    for(int l=cnt,r=cnt,num=0,sum[2]={0};l>=1;--l) {
        num+=sta[l]*(l&1);
        sum[0]+=sta[l],sum[1]+=sta[l]*(l&1);
        while (sum[0]>2*len) sum[0]-=sta[r],sum[1]-=sta[r]*(r&1),--r;
        ans=min(ans,tot-sum[1]-(r+1<=cnt&&r+1&1)*(2*len-sum[0]));
    }
 
    for(int l=cnt,r=cnt,num=0,sum[2]={0};l>=1;--l) {
        num+=sta[l]*(l&1);
        sum[0]+=sta[l],sum[1]+=sta[l]*(l&1);
        while (sum[0]>len) sum[0]-=sta[r],sum[1]-=sta[r]*(r&1),--r;
        g[l]=num-sum[1]-(r+1<=cnt&&r+1&1)*(len-sum[0]);
    }
    per(i,cnt-1,1) g[i]=min(g[i],g[i+1]+sta[i]*(i&1));
    for(int l=1,r=1,num=0,sum[2]={0};l<=cnt;++l) {
        num+=sta[l]*(l&1);
        sum[0]+=sta[l],sum[1]+=sta[l]*(l&1);
        while (sum[0]>len) sum[0]-=sta[r],sum[1]-=sta[r]*(r&1),++r;
        ans=min(ans,g[l+1]+num-sum[1]-(r-1>=1&&r-1&1)*(len-sum[0]));
    }
 
    printf("%d\n",ans);
}
 
int main() {
    //freopen("a.txt","r",stdin);
    int test_;
    scanf("%d",&test_);
    while (test_--) {
 
        scanf("%d%d%d%d%d",&n,&m,&S,&T,&len);
        ++S,++T;
        rep(i,1,m) {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            ++x,++y;
            e_add(x,y,z);
        }
 
 
        dijkstra();
 
        if(dis[T]>1000000000) puts("-1");
        else{
            make_dominator_tree();
            get_ans();
        }
 
        e_size=0;
        rep(i,0,n+m) f[i]=g[i]=be[i]=fa[i]=id[i]=st[i]=vis[i]=sta[i]=idom[i]=sdom[i]=head[i]=0;
        rep(i,1,n+m) to[i].clear(),pre[i].clear(),buc[i].clear();
    }
}
bzoj 3281

 

bzoj 3495

2-sat

加一个前缀和优化即可

#include <set>
#include <stack>
#include <ctime>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#define fir first
#define sec second
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(l);i>=(r);--i)
using namespace std;
typedef long long s64;
 
const int M=4e6+5;
int n,m,K;
int a[M],be[M];
int low[M],dfn[M],time_;
stack <int> sta;
 
int e_size,head[M];
struct edge{
    int v,nxt;
}e[M*5];
 
void e_add(int u,int v) {
    e[++e_size]=(edge){v,head[u]};
    head[u]=e_size;
}
 
void tarjan(int x) {
    //cout<<"-_-"<<x<<endl;
    low[x]=dfn[x]=++time_;
    sta.push(x);
 
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        //cout<<x<<" "<<v<<endl;
        if(!dfn[v]) {
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(!be[v]) low[x]=min(low[x],dfn[v]);
    }
 
    if(low[x]==dfn[x]) {
        ++be[0];
        while (1) {
            int tmp=sta.top();
            sta.pop();
            be[tmp]=be[0];
            if(x==tmp) break;
        }
    }
}
 
 
int main() {
    //freopen("a.txt","r",stdin);
    scanf("%d%d%d",&n,&m,&K);
    rep(i,1,m) {
        int x,y;
        scanf("%d%d",&x,&y);
        e_add(2*x-1,2*y);
        e_add(2*y-1,2*x);
    }
 
    int cnt=2*n;
    rep(i,1,K) {
        //cout<<"-_-"<<endl;
        int num;
        scanf("%d",&num);
        rep(j,1,num) scanf("%d",a+j);
 
        int pre=2*a[1]-1;
        rep(j,2,num) {
            e_add(2*a[j],pre);
            ++cnt;
            e_add(cnt,2*a[j]-1);
            e_add(cnt,pre);
            pre=cnt;
        }
 
        pre=2*a[num]-1;
        per(j,num-1,1) {
            e_add(2*a[j],pre);
            ++cnt;
            e_add(cnt,2*a[j]-1);
            e_add(cnt,pre);
            pre=cnt;
        }
    }
 
    rep(i,1,2*n) if(!dfn[i]) tarjan(i);
 
    rep(i,1,n) if(be[2*i]==be[2*i-1]) return puts("NIE"),0;
    puts("TAK");
}
bzoj 3495

 

bzoj 2730

点双连通分量

分析后发现给只包含一个割点的强连通分量放一个出口即可

特判没有割点的情况

#include <set>
#include <stack>
#include <ctime>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#define fir first
#define sec second
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(l);i>=(r);--i)
using namespace std;
typedef long long s64;
typedef unsigned long long u64;
 
const int M=1e4+5;
 
int n,m;
int e_size,head[M];
int low[M],dfn[M],time_,be;
bool is_cut[M];
 
vector <int> cc[M];
 
stack <int> sta;
 
struct edge{
    int v,nxt;
}e[M*5];
 
void e_add(int u,int v) {
    e[++e_size]=(edge){v,head[u]};
    head[u]=e_size;
}
 
 
void tarjan(int x,int las) { 
    low[x]=dfn[x]=++time_;
 
    sta.push(x);
 
    int c=0;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==las) continue;
        if(!dfn[v]) {
            int pre=sta.top();
            tarjan(v,x);
            low[x]=min(low[x],low[v]);
            if(low[v]>=dfn[x]) {
                ++c;
                is_cut[x]=1;
 
                ++be;
                while (1) {
                    int tmp=sta.top();
                    if(tmp==pre) break;
                    sta.pop();
                    cc[be].push_back(tmp);
                }
                cc[be].push_back(x);
            }
        }
        else low[x]=min(low[x],dfn[v]);
    }
 
    if(x==las&&c==1) is_cut[x]=0;
}
 
 
int main() {
    //freopen("a.txt","r",stdin);
    int test_=0;
    while (scanf("%d",&m)==1) {
        if(!m) break;
        n=0;
        rep(i,1,m) {
            int x,y;
            scanf("%d%d",&x,&y);
            n=max(n,max(x,y));
            e_add(x,y),e_add(y,x);
        }
 
        rep(i,1,n) if(!dfn[i]) tarjan(i,i);
 
        if(be==1) {
            printf("Case %d: 2 %lld\n",++test_,1ll*n*(n-1)/2);
        }
        else {
            u64 ans[2]={0};
            ans[1]=1;
            rep(i,1,be) {
                int t=0;
                for(int j=cc[i].size()-1;j>=0;--j) t+=is_cut[cc[i][j]];
                if(t==1) ++ans[0],ans[1]*=cc[i].size()-1;
            }
            printf("Case %d: %llu %llu\n",++test_,ans[0],ans[1]);
        }
 
        time_=e_size=0;
        rep(i,1,n) low[i]=dfn[i]=head[i]=is_cut[i]=0;
        rep(i,1,be) cc[i].clear();
        be=0;
    }
}
bzoj 2730

 

bzoj 5219

竞赛图计数简单题

#include <set>
#include <stack>
#include <ctime>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#define fir first
#define sec second
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(l);i>=(r);--i)
using namespace std;
typedef long long s64;
typedef unsigned long long u64;
 
 
const int M=2e3+5;
 
int n,mod;
int C[M][M];
int f[M],g[M],bin[M];
 
int qpow(int x,int k) {
    int t=1;
    for(;k;k>>=1,x=1ll*x*x%mod) if(k&1) t=1ll*t*x%mod;
    return t;
}
 
void inc(int &x,int y) {x+=y,x-=x>=mod?mod:0;}
 
int main() {
    //freopen("a.txt","r",stdin);
    scanf("%d%d",&n,&mod);
    rep(i,0,n) C[i][0]=1;
    rep(i,1,n) rep(j,1,i) inc(C[i][j]=C[i-1][j],C[i-1][j-1]);
 
    rep(i,0,n) bin[i]=qpow(2,i*(i-1)>>1);
 
    rep(i,1,n) {
        g[i]=bin[i];
        rep(j,1,i-1) inc(g[i],mod-1ll*C[i][j]*g[j]%mod*bin[i-j]%mod);
    }
 
    //rep(i,1,n) cout<<g[i]<<" "; cout<<endl;
    rep(i,1,n) {
        int ans=0;
        rep(j,0,i-1) inc(ans,1ll*C[i-1][j]*g[j+1]%mod*bin[i-j-1]%mod);
        ans=1ll*ans*C[n-1][i-1]%mod*bin[n-i]%mod;
        printf("%d\n",ans);
    }
    puts("");
}
bzoj 5219

 

bzoj 3693

Hall定理

求$|S|-|T|$最小值显然枚举的$|S|$中的组的区间并是连续的

转化为枚举区间,求出区间包含的组的$a_{i}$的和即可

左端点单调用线段树维护右端点的区间加减求min即可

$O(n*logn)$

#include <set>
#include <stack>
#include <ctime>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define fir first
#define sec second
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(l);i>=(r);--i)
using namespace std;
typedef long long s64;
typedef unsigned long long u64;
 
const int M=5e5+5;
int n,m;
int st[M],sta[M];
int Min[M*4],data[M*4];
  
struct node{
    int x,id;
  
    bool operator <(const node &a) const {
        return x<a.x;
    }
}p[M];
  
  
struct point {
    int l,r,x;
  
    bool operator <(const point &a) const {
        return l<a.l;
    }
}a[M];
  
void push_down(int g) {
    data[g<<1]+=data[g];
    data[g<<1|1]+=data[g];
  
    Min[g<<1]+=data[g];
    Min[g<<1|1]+=data[g];
      
    data[g]=0;
}
  
  
void T_add(int g,int l,int r,int lx,int rx,int x) {
    if(lx<=l&&rx>=r) return Min[g]+=x,data[g]+=x,void();
  
    if(data[g]) push_down(g);
  
    int mid=l+r>>1;
    if(lx<=mid) T_add(g<<1,l,mid,lx,rx,x);
    if(rx>mid)  T_add(g<<1|1,mid+1,r,lx,rx,x);
  
    Min[g]=min(Min[g<<1],Min[g<<1|1]);
}
  
int query(int g,int l,int r,int lx,int rx) {
    if(lx<=l&&rx>=r) return Min[g];
  
    if(data[g]) push_down(g);
  
    int ans=2e9;
    int mid=l+r>>1;
    if(lx<=mid) ans=min(ans,query(g<<1,l,mid,lx,rx));
    if(rx>mid)  ans=min(ans,query(g<<1|1,mid+1,r,lx,rx));
    return ans;
}
  
signed main() {
    //freopen("a.txt","r",stdin);
    //freopen("a.out","w",stdout);
    int test_;
    scanf("%d",&test_);
    while (test_--) {
        scanf("%d%d",&n,&m);
  
        s64 sum=0;
        rep(i,1,n) {
            scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].x);
            if(a[i].l>a[i].r) a[i].r+=m;
            sum+=a[i].x;
        }
        if(sum>m) {
            puts("No");
            continue;
        }
 
        int cnt=n;
        rep(i,1,n) if(a[i].r<m) a[++cnt]=(point){a[i].l+m,a[i].r+m,a[i].x};
        n=cnt;
  
        rep(i,1,n) p[2*i-1]=(node){a[i].l,2*i-1},p[2*i]=(node){a[i].r,2*i};
        sort(p+1,p+2*n+1);
        p[0].x=p[1].x-1;
        rep(i,1,2*n) {
            if(p[i].x!=p[i-1].x) ++st[0];
            st[st[0]]=p[i].x;
            sta[p[i].id]=st[0];
        }
        rep(i,1,n) a[i].l=sta[2*i-1],a[i].r=sta[2*i];
  
        sort(a+1,a+n+1);
        rep(i,1,st[0]) T_add(1,1,st[0],i,i,st[i]-st[1]+1);
        rep(i,1,n) T_add(1,1,st[0],a[i].r,st[0],-a[i].x);
        //rep(i,1,st[0]) cout<<query(1,1,st[0],i,i)<<" "; cout<<endl;while (1);
  
        int ans=0;
        int head_=1,tail_=1;
        rep(i,1,st[0]) {
            while (tail_+1<=st[0]&&st[tail_+1]-st[i]<m) ++tail_;
            ans=query(1,1,st[0],i,tail_);
            if(ans<0) break;
  
            while (a[head_].l==i) T_add(1,1,st[0],a[head_].r,st[0],a[head_].x),++head_;
            T_add(1,1,st[0],i,st[0],st[i]-st[i+1]);
        }
        ans<0?puts("No"):puts("Yes");
 
        st[0]=0;
        rep(i,0,16*n) Min[i]=data[i]=0;
    }
}
bzoj 3693

 

bzoj 3894

最小割

将st看作文理

新建(s,x',same_art)并用same_art限制5个点即可

same_sci同理对称新建点即可

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=r;i>=l;--i)
using namespace std;
typedef long long s64;
 
const int N=105;
const int M=4e4+5;
const int inf=2e9;
  
int n,m;
int art[N][N],sci[N][N];
int same_art[N][N],same_sci[N][N];
int S,T,dep[M],e_size,head[M];
int x_[4]={0,0,1,-1},y_[4]={1,-1,0,0};
  
struct edge {
    int v,w,nxt;
}e[M*10];
  
void e_add(int u,int v,int w) {
    e[++e_size]=(edge){v,w,head[u]};
    head[u]=e_size;
}
 
void insert(int u,int v,int w) {
    e_add(u,v,w),e_add(v,u,0);
}
  
  
bool Bfs() {
    queue <int> q;
    memset(dep,0,sizeof(dep));
    dep[S]=1;
    q.push(S);
    while (!q.empty()) {
        int r=q.front();
        q.pop();
        for(int i=head[r];i;i=e[i].nxt) {
            int v=e[i].v;
            if(!dep[v]&&e[i].w) {
                dep[v]=dep[r]+1;
                q.push(v);
                if(v==T) return 1;
            }
        }
    }
    return 0;
}
  
int Dfs(int x,int cp) {
    if(x==T) return cp;
    int las=cp,q;
    for(int i=head[x];i;i=e[i].nxt) {
        int v=e[i].v;
        if(dep[v]==dep[x]+1&&e[i].w&&las) {
            q=Dfs(v,min(las,e[i].w));
            if(!q) {dep[v]=0;continue;}
            e[i].w-=q,las-=q,e[i^1].w+=q;
            if(!las) break;
        }
    }
    return cp-las;
}
  
int main() {
    //freopen("a.txt","r",stdin);
    S=M-2,T=M-1;
    e_size=1;
 
    scanf("%d%d",&n,&m);
    rep(i,1,n) rep(j,1,m) scanf("%d",art[i]+j);
    rep(i,1,n) rep(j,1,m) scanf("%d",sci[i]+j);
    rep(i,1,n) rep(j,1,m) scanf("%d",same_art[i]+j);
    rep(i,1,n) rep(j,1,m) scanf("%d",same_sci[i]+j);
 
 
    int ans=0;
    rep(i,1,n) rep(j,1,m) {
        ans+=art[i][j]+sci[i][j];
        ans+=same_art[i][j]+same_sci[i][j];
        int x=(i-1)*m+j;
        insert(S,x,art[i][j]);
        insert(x,T,sci[i][j]);
        insert(x,x+n*m,inf);
        insert(x+n*m,T,same_sci[i][j]);
        insert(S,x+2*n*m,same_art[i][j]);
        insert(x+2*n*m,x,inf);
 
        rep(k,0,3) {
            int ii=i+x_[k],jj=j+y_[k];
            if(ii<1||ii>n||jj<1||jj>m) continue;
            int xx=(ii-1)*m+jj;
 
            insert(x+2*n*m,xx,inf);
            insert(xx,x+n*m,inf);
        }
    }
 
    while (Bfs()) ans-=Dfs(S,inf);
    cout<<ans<<endl;
}
bzoj 3894

 

bzoj 3436

差分约束裸题

 

posted @ 2019-06-17 11:33  asd123www  阅读(313)  评论(0编辑  收藏  举报