[JOISC 2014] 電圧 题解
[JOISC 2014] 電圧 题解
赛时都想到了我也不知道为啥自己没敢写
首先题意可以转化为,我们去掉一个边后,剩下的图可以黑白染色,同时保证去掉的边两端的点颜色相同,问这样的边数。换句话说,去掉一条边后,剩下的图应该是一个二分图。
然后我们很容易想到线段树分治来处理这种问题。每次只有一条边被删掉,那我们可以令第
当然,我们还得验证去掉的边两端可以染成一种颜色。我们用扩展域并查集来做,只需判断一下
代码:
#include<bits/stdc++.h> using namespace std; const int N = 1e5+100, M = 2e5+10; int read() { int x = 0; char ch = getchar(); while(ch<'0' || ch>'9') ch = getchar(); while(ch>='0'&&ch<='9') x = x*10+(ch-48), ch = getchar(); return x; } //断开每一条边判断是否为二分图 -> 一条边存在于 1 - i-1, i+1 - n int n, m; struct Edge{ int u, v; }e[M]; struct xwx{ int son, fa, val; }stk[M<<1]; int top; struct DSU{ int fa[N<<1], siz[N<<1]; void init() { for(int i = 1; i<=n*2; ++i) { fa[i] = i, siz[i] = 1; } } int find(int x) { while(x != fa[x]) x = fa[x]; return x; } void merge(int x, int y) { x = find(x), y = find(y); if(x == y) { return; } if(siz[x] > siz[y]) swap(x, y); fa[x] = y; siz[y]+=siz[x]; stk[++top] = (xwx) {x, y, siz[x]}; return; } }dsu; int ans; struct SegmentTree{ vector<int> tree[M<<2]; #define ls tr<<1 #define rs tr<<1 | 1 void modify(int tr, int L, int R, int lq, int rq, int id) { if(lq == L && R == rq) { tree[tr].push_back(id); return; } int mid = (L+R)>>1; if(lq <= mid) modify(ls, L, mid, lq, min(rq, mid), id); if(mid < rq) modify(rs, mid+1, R, max(mid+1, lq), rq, id); } void solve(int tr, int L, int R, bool flag) { int u, v; int st = top; for(int id : tree[tr]) { u = e[id].u, v = e[id].v; dsu.merge(u, v + n); dsu.merge(v, u + n); if(dsu.find(u) == dsu.find(v)) flag = 0; } if(L == R) { if(flag) { u = e[L].u, v = e[L].v; if(dsu.find(u) != dsu.find(v+n)) ++ans; } while(top > st) { xwx tmp = stk[top]; dsu.fa[tmp.son] = tmp.son; dsu.siz[tmp.fa] -= tmp.val; --top; } return; } int mid = (L+R)>>1; solve(ls, L, mid, flag); solve(rs, mid+1, R, flag); while(top > st) { xwx tmp = stk[top]; dsu.fa[tmp.son] = tmp.son; dsu.siz[tmp.fa] -= tmp.val; --top; } } }seg; int main() { n = read(), m = read(); for(int i = 1; i<=m; ++i) { e[i] = (Edge){read(), read()}; } dsu.init(); for(int i = 1; i<=m; ++i) { if(i > 1) seg.modify(1, 1, m, 1, i-1, i); if(i < m) seg.modify(1, 1, m, i+1, m, i); } seg.solve(1, 1, m, 1); printf("%d\n", ans); return 0; }