[HAOI2017]新型城市化

orz栋爷教我的这题
http://blog.csdn.net/werkeytom_ftd/article/details/72992793

#include <bits/stdc++.h>
#define N 20050
#define M 1000050
#define INF (1<<29)
using namespace std;
typedef pair<int,int> pii;

int h[N],p[N],cur[N],tmp[N],pmt[N],rec[N],S,T,tp,pt,L[N],R[N],tot,sum,cnt;
int A[M],B[M],o[M],t[N],g[N],ans,ttt;
int dfn[N],low[N],ins[N],gS[N],gT[N],tme,ggg;
stack<int> sta;
int n,m;
pii pr[M];
bool vis[N];

inline int rd() {int r;scanf("%d",&r);return r;}

struct Edge{int a,b,v,n,mark;}e[M], idEdge;
void insert(int a,int b,int v,int m) {
    e[++cnt] = (Edge){a,b,v,h[a],m}, h[a] = cnt;
    e[++cnt] = (Edge){b,a,0,h[b],m}, h[b] = cnt;
}

vector<int> E[N],V[N];
void link(int a, int b, int x) {
    E[a].push_back(b), E[b].push_back(a);
    V[a].push_back(x), V[b].push_back(x);
}

void dfs(int u,int x) {
    vis[u] = 1;
    !x ? tmp[++tp] = u : pmt[++pt] = u;
    for (int i=0;i<(int)E[u].size();i++)
        if (!vis[ E[u][i] ]) dfs(E[u][i], x^1);
}

bool BFS() {
    bool flag = 0;
    ttt++;

    for (int _=1;_<=tot;_++) p[_] = 0, cur[_] = h[_];
    queue<int> q;
    t[S] = ttt;
    q.push(S);
    p[S] = 1;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        if (u == T) flag = 1;
        for (int i=h[u];i;i=e[i].n) {
            int v = e[i].b, cp = e[i].v;
            if (cp > 0 && t[v]<ttt)
                t[v] = ttt, p[v] = p[u] + 1, q.push(v);
        }
    }
    return flag;
}

int DFS(int u,int fl) {
    if (u == T) return fl;
    int g=0, f=fl;
    for (int i=cur[u];i;i=e[i].n) {
        cur[u] = i;
        int v = e[i].b, cp = e[i].v, tmp = 0;
        if (p[v] == p[u]+1 && cp>0 && (tmp=DFS(v,min(cp,f))) > 0) {
            g += tmp, f -= tmp;
            e[i^1].v += tmp, e[i].v -= tmp;
        }
        if (!f) break;
    }
    return g;
}

void Tarjan(int u) {
    dfn[u] = low[u] = ++tme;
    sta.push(u); ins[u] = 1;
    for (int i=h[u];i;i=e[i].n) if (e[i].v){
        int v = e[i].b;
        if (!dfn[v]) {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        } else {
            if (ins[v]) low[u] = min(low[u], dfn[v]);
        }
    }
    if (low[u] == dfn[u]) {
        ++ggg;
        do {
            int cur = sta.top(); sta.pop();
            ins[cur] = 0;
            g[cur] = ggg;
        } while (ins[u]);
    }
}

void find() {
    for (int i=1;i<=tot;i++) gS[i] = gT[i] = 0;
    queue<int> q;
    q.push(S);
    gS[S] = 1;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int i=h[u];i;i=e[i].n) {
            int v = e[i].b, cp = e[i].v;
            if (cp > 0 && !gS[v])
                gS[v] = 1, q.push(v);
        }
    }

    q.push(T);
    gT[T] = 1;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int i=h[u];i;i=e[i].n) {
            int v = e[i].b, cp = e[i^1].v;
            if (cp > 0 && !gT[v])
                gT[v] = 1, q.push(v);
        }
    }

}

int main() {
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    n = rd(), m = rd();
    for (int _=1;_<=m;_++) {
        A[_] = rd(), B[_] = rd();
        link(A[_], B[_], _);
    }

    for (int _=1;_<=n;_++) if (!vis[_]) {
        tp = pt = 0;
        dfs(_, 0);      

        //init
        for (int _=1;_<=cnt;_++) e[_] = idEdge;
        for (int _=1;_<=tot;_++) h[_] = 0;
        tot = 0, cnt = 1, sum = 0;

        S = ++tot, T = ++tot;
        for (int i=1;i<=tp;i++) L[tmp[i]] = ++tot, insert(S, L[ tmp[i] ], 1, 0), rec[L[tmp[i]]] = cnt-1;
        for (int i=1;i<=pt;i++) R[pmt[i]] = ++tot, insert(R[ pmt[i] ], T, 1, 0), rec[R[pmt[i]]] = cnt-1;
        for (int i=1;i<=tp;i++) {
            for (int j=0;j<(int)E[tmp[i]].size();j++) {
                int A = tmp[i], B = E[tmp[i]][j];
                insert(L[A], R[B], 1, V[A][j]);
            }
        }

        while (BFS()) sum += DFS(S, INF);
        for (int i=1;i<=tot;i++) dfn[i] = low[i] = g[i] = 0;

        for (int i=1;i<=tot;i++) if (!dfn[i]) Tarjan(i); 
        find();

        for (int i=2;i<=cnt;i+=2)
            if (e[i].mark && e[i^1].v) {
                int x = e[i].mark;
                o[x] = 1;
                if (g[e[i].a] == g[e[i].b]) o[x] = 0;
                if (gS[e[i].b]) o[x] = 0;
                if (gT[e[i].a]) o[x] = 0;
            }
    }


    for (int _=1;_<=m;_++) ans += o[_];
    printf("%d\n",ans);
    for (int _=1;_<=m;_++) if (A[_]>B[_]) swap(A[_], B[_]);
    int tp = 0;
    for (int _=1;_<=m;_++)
        o[_] ? pr[++tp] = pii(A[_], B[_]),0 :0;
    sort(pr+1,pr+tp+1);
    for (int _=1;_<=tp;_++)
        printf("%d %d\n",pr[_].first,pr[_].second);

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值