关于此题的一个想法
查看原帖
关于此题的一个想法
573341
MiniLong楼主2023/7/12 09:54

根据题目性质可知,先不管行之间的连边,任意两行列之间的连边都是相同的,这个性质就很好。

然后有一个可能成立的结论:可以先算出来两行之间列连边中 有连边 的点之间的联通块数量,再算出来三行之间两两相连的列连边中 有连边 的联通块数量。最后用个并查集维护行之间的连边,维护一下行之间的联通块的 sizsiz 和答案。加入一条边时若原本在一个并查集中就用第二种答案,若不在同一个就把两个联通块的答案和第一种答案取 min⁡\min,就是当前联通块的答案。

最后加上没有连边的答案就行。

但是 WA 了 3 个点,有无大佬能 hack 一下这个想法。

codecode 如下

#include <bits/stdc++.h>
#define int long long
#define _rep(i, x, y) for(int i = x; i <= y; ++i)
#define _req(i, x, y) for(int i = x; i >= y; --i)
#define _rev(i, u) for(int i = head[u]; i; i = e[i].nxt)
#define pb push_back
#define fi first
#define se second
#define mst(f, i) memset(f, i, sizeof f)
using namespace std;
#ifdef ONLINE_JUDGE
#define debug(...) 0
#else
#define debug(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#endif
namespace fastio{
    char ibuf[50007],*p1 = ibuf, *p2 = ibuf;
    #ifdef ONLINE_JUDGE
    #define get() p1 == p2 && (p2 = (p1 = ibuf) + fread(ibuf, 1, 50007, stdin), p1 == p2) ? EOF : *p1++
    #else
    #define get() getchar()
    #endif
    template<typename T> inline void read(T &t){
        T x = 0, f = 1;
        char c = getchar();
        while(!isdigit(c)){
            if(c == '-') f = -f;
            c = getchar();
        }
        while(isdigit(c)) x = x * 10 + c - '0', c = getchar();
        t = x * f;
    }
    template<typename T, typename ... Args> inline void read(T &t, Args&... args){
        read(t);
        read(args...);
    }
    template<typename T> void write(T t){
        if(t < 0) putchar('-'), t = -t;
        if(t >= 10) write(t / 10);
        putchar(t % 10 + '0');
    }
    template<typename T, typename ... Args> void write(T t, Args... args){
        write(t), putchar(' '), write(args...);
    }
    template<typename T> void writeln(T t){
        write(t);
        puts("");
    }
    template<typename T> void writes(T t){
        write(t), putchar(' ');
    }
    #undef get
};
using namespace fastio;
#define multitest() int T; read(T); _rep(tCase, 1, T)
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e5 + 5;
int n, m, cnt, cur, cnt2, fa[N], siz[N], res[N];
PII e[N];
bool vis[N], num[N];
int find(int u){return fa[u] == u ? u : fa[u] = find(fa[u]);}
void merge(int u, int v){
	int fx = find(u), fy = find(v);
	if(fx == fy) return;
	if(siz[fx] > siz[fy]) swap(fx, fy);
	fa[fx] = fy, siz[fy] += siz[fx], res[fy] = min(res[fy], res[fx]);
}
ll ans;
signed main(){
	read(n, m);
	_rep(i, 1, 2 * n) siz[fa[i] = i] = 1;
	_rep(i, 1, m) read(e[i].fi, e[i].se), merge(e[i].fi, e[i].se + n), merge(e[i].se, e[i].fi + n), num[e[i].fi] = num[e[i].se] = 1;
	_rep(i, 1, n) cur += !num[i];
	
	
	_rep(i, 1, n){
		if(vis[find(i)] || !num[i]) continue;
		vis[find(i)] = 1, cnt++;
	} 
	_rep(i, 1, 3 * n) vis[fa[i] = i] = 0, siz[i] = 1;
	_rep(i, 1, m){
		merge(e[i].fi, e[i].se + n), merge(e[i].se, e[i].fi + n);
		merge(e[i].fi, e[i].se + n + n), merge(e[i].se, e[i].fi + n + n);
		merge(e[i].fi + n, e[i].se + n + n), merge(e[i].se + n, e[i].fi + n + n);
	}
	_rep(i, 1, n){
		if(vis[find(i)] || !num[i]) continue;
		vis[find(i)] = 1, cnt2++;
	}
//	writeln(cnt2);
	_rep(i, 1, n) vis[fa[i] = i] = 0, siz[i] = 1, res[i] = cnt;
	_rep(i, 1, m){
		if(find(e[i].fi) == find(e[i].se)){
			res[find(e[i].fi)] = cnt2;
			continue;
		}
		merge(e[i].fi, e[i].se);	
	}
	_rep(i, 1, n){
		if(!num[i]){
			ans += n;
			continue;
		}
		int x = find(i);
		if(vis[x]) continue;
		vis[x] = 1, ans += res[x] + cur * siz[x];
	}
	writeln(ans);
    return 0;
}
2023/7/12 09:54
加载中...