zoj - 4059 Kawa Exam scc + dsu

Kawa Exam

题解:先scc把图变成树, 然后对于这若干棵树在进行dsu的操作。

dsu就是先找到最大的子树放在一边,然后先处理小的子树,最后处理大的子树。无限递归。

重要的一点就是 是否重新添加每个点的值,每次处理完小的子树之后会清空影响,然后处理完最大的子树之后就不再清空影响,这样减少复杂度。 

代码:

#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod =  (int)1e9+7;
const int N = 2e5 + 100;
int head[N], to[N<<1], nt[N<<1], tot = 0;
void add(int u, int v){
    to[tot] = v;
    nt[tot] = head[u];
    head[u] = tot++;
}
int belong[N], dfn[N], low[N], now_time, scc_cnt;
int now = 0, st[N], ed[N];
vector<int> vc[N];
vector<pll> e[N];
stack<int> s;
void dfs(int u, int id){
    dfn[u] = low[u] = ++now_time;
    s.push(u);
    for(int i = head[u]; ~i; i = nt[i]){
        if(i == (id^1)) continue;
        if(!dfn[to[i]]) dfs(to[i], i);
        if(!belong[to[i]]) low[u] = min(low[u], low[to[i]]);
    }
    if(dfn[u] == low[u]){
        ++scc_cnt;
        int now;
        while(1){
            now = s.top(); s.pop();
            belong[now] = scc_cnt;
            vc[scc_cnt].pb(now);
            if(now == u) break;
        }
    }
}
void scc(int n){
    for(int i = 1; i <= scc_cnt; ++i) {
        vc[i].clear();
        e[i].clear();
        st[i] = ed[i] = 0;

    } now = 0;
    for(int i = 1; i <= n; ++i) dfn[i] = low[i] = belong[i] = 0;
    while(!s.empty()) s.pop();
    now_time = scc_cnt = 0;
    for(int i = 1; i <= n; ++i)
        if(!belong[i]) dfs(i,-1);
     for(int i = 0, u, v; i <= tot; i += 2){
        u = to[i], v = to[i+1];
        u = belong[u], v = belong[v];
        if(u != v) e[u].pb(pll(v,i/2+1)), e[v].pb(pll(u,i/2+1));
    }
}
int vis[N], col[N], col2[N], cnt[N], cnt2[N], mx1, mx2;
int sz[N], p[N];
int a[N];
void Add1(int u){
    for(int i = 0, x; i < vc[u].size(); ++i){
        x = vc[u][i];
        cnt[col[a[x]]]--;
        ++col[a[x]];
        cnt[col[a[x]]]++;
        if(mx1 < col[a[x]]) mx1 = col[a[x]];
    }
}
void Add2(int u){
    for(int i = 0, x; i < vc[u].size(); ++i){
        x = vc[u][i];
        cnt2[col2[a[x]]]--;
        ++col2[a[x]];
        cnt2[col2[a[x]]]++;
        if(mx2 < col2[a[x]]) mx2 = col2[a[x]];
    }
}
void Sub1(int u){
    for(int i = 0, x; i < vc[u].size(); ++i){
        x = vc[u][i];
        --cnt[col[a[x]]];
        --col[a[x]];
        ++cnt[col[a[x]]];
        if(cnt[mx1] == 0) --mx1;
    }
}
void Sub2(int u){
    for(int i = 0, x; i < vc[u].size(); ++i){
        x = vc[u][i];
        --cnt2[col2[a[x]]];
        --col2[a[x]];
        ++cnt2[col2[a[x]]];
        if(cnt2[mx2] == 0) --mx2;
    }
}
void ddfs(int o, int u){
    //cout << o << ' ' << u << endl;
    ++now;
    Add1(u);
    p[now] = u;
    st[u] = now;
    sz[u] = vc[u].size();
    for(int i = 0, v; i < e[u].size(); ++i){
        v = e[u][i].fi;
        if(v == o) continue;
        ddfs(u, v);
        sz[u] += sz[v];
    }
    ed[u] = now;
}
void Clear(int o, int u){
    Sub1(u);
   for(int i = 0; i < e[u].size(); ++i){
        int v = e[u][i].fi;
        if(v == o) continue;
        Clear(u, v);
    }
}
int ttttmp;
int val[N];
void dsu(int o, int u, int op, int id){
    int bigson = -1, mx = -1, iid;
    for(int i = 0, v; i < e[u].size(); ++i){
        v = e[u][i].fi;
        if(v == o) continue;
        if(mx < sz[v]) {
            mx = sz[v];
            bigson = v;
            iid = e[u][i].se;
        }
    }
    for(int i = 0, v; i < e[u].size(); ++i){
        v = e[u][i].fi;
        if(v == o || v == bigson) continue;
        dsu(u, v, 0, e[u][i].se);
    }
    if(bigson != -1)
        dsu(u, bigson, 1, iid);
    for(int i = 0, v; i < e[u].size(); ++i){
        v = e[u][i].fi;
        if(v != o && v != bigson)   {
            for(int i = st[v]; i <= ed[v]; i++){
                Sub1(p[i]);
                Add2(p[i]);
            }
        }
    }
    Sub1(u);
    Add2(u);
    val[id] = mx1+mx2-ttttmp;
    if(op == 0){
        for(int i = st[u]; i <= ed[u]; i++){
            Sub2(p[i]);
            Add1(p[i]);
        }
    }
}
void init(){
    memset(head, -1, sizeof(head));
    tot = 0;
}
int main(){
    int T, n, m;
    scanf("%d", &T);

    while(T--){
        init();
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        for(int i = 1, u, v; i <= m; ++i){
            scanf("%d%d", &u, &v);
            add(u,v); add(v,u);
        }
        scc(n);
        int ans = 0;
        for(int i = 1; i <= scc_cnt; ++i){
            if(st[i]) continue;
            mx1 = mx2 = 0;
            ddfs(0,i);
            ttttmp = mx1;
            ans += mx1;
            dsu(0,i,0,0);
            Clear(0,i);
        }
//        cout << ans << endl;
        for(int i = 1; i <= m; i++){
            printf("%d%c", ans+val[i]," \n"[i==m]);
            val[i] = 0;
        }
    }
    return 0;
}
/*
3
7 5
1 2 1 2 1 2 1
1 2
1 3
2 4
5 6
5 7
3 3
1 2 3
1 2
1 3
2 3
7 5
1 2 1 2 1 2 1
1 2
1 3
2 4
5 6
5 7
*/
View Code

 

posted @ 2018-11-11 14:20  Schenker  阅读(262)  评论(0编辑  收藏  举报