bzoj3237 [Ahoi2013]连通图
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3237
【题解】
先写了一个对询问分治然后不断加边的分治。
发现有可能一条边在几乎每个分治区间都会判,就gg了。
然后get一个比较正常的idea,就是我计算总删边次数cnt,先把没删的添加到边集中。
在分治[l,r]的时候,考虑[l,mid]对[mid+1,r]的影响,把[l,mid]删过的边先在cnt里扣去。
每当一个数被扣到0,也就是意思是在[mid+1,r]没被删了,就加到边集中,递归分治[mid+1,r]
否则就撤回刚刚的操作,用[mid+1,r]对[l,mid]做一遍。
复杂度O(nlog^2n)
这样实质还是边有没有用到的问题,只是一个小小的实现技巧。
# include <stdio.h> # include <assert.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10, N = 1e6 + 10; const int mod = 1e9+7; # define RG register # define ST static int n, m, del[M]; struct edge { int u, v; edge() {} edge(int u, int v) : u(u), v(v) {} inline void set() { scanf("%d%d", &u, &v); } }t[M], e[M]; struct quest { int c, p[5]; inline void set() { scanf("%d", &c); for (int i=1; i<=c; ++i) { scanf("%d", &p[i]); del[p[i]] ++; } } }q[M]; int st[N], stn=0; struct us { int n, fa[M], rk[M]; inline void set(int _n) { n = _n; for (int i=1; i<=n; ++i) fa[i] = i, rk[i] = 1; } inline int getf(int x) { return fa[x] == x ? x : getf(fa[x]); } inline void un(int x, int y) { x = getf(x), y = getf(y); if(x == y) return; if(rk[x] > rk[y]) swap(x, y); if(rk[x] == rk[y]) ++rk[y], st[++stn] = -y; fa[x] = y; st[++stn] = x; -- n; } inline void re() { int x = st[stn]; --stn; if(x<0) -- rk[-x]; else fa[x] = x, ++ n; } }E; bool ans[M]; bool u[M]; inline void solve(int ql, int qr) { // cout << ql << ' ' << qr << ' ' << E.n << endl; if(E.n == 1) { for (int i=ql; i<=qr; ++i) ans[i] = 1; return ; } if(ql == qr) return ; int qmid = ql + qr >> 1, cur_stn = stn; for (int i=ql, ps; i<=qmid; ++i) for (int j=1; j<=q[i].c; ++j) { --del[ps = q[i].p[j]]; if(del[ps] == 0) E.un(e[ps].u, e[ps].v); } solve(qmid+1, qr); for (int i=ql; i<=qmid; ++i) for (int j=1; j<=q[i].c; ++j) ++del[q[i].p[j]]; while(stn != cur_stn) E.re(); for (int i=qmid+1, ps; i<=qr; ++i) for (int j=1; j<=q[i].c; ++j) { --del[ps = q[i].p[j]]; if(del[ps] == 0) E.un(e[ps].u, e[ps].v); } solve(ql, qmid); for (int i=qmid+1; i<=qr; ++i) for (int j=1; j<=q[i].c; ++j) ++del[q[i].p[j]]; while(stn != cur_stn) E.re(); } int main() { int en = 0; cin >> n >> m; E.set(n); for (int i=1; i<=m; ++i) e[i].set(); int Q; cin >> Q; for (int i=1; i<=Q; ++i) q[i].set(); for (int i=1; i<=m; ++i) if(!del[i]) E.un(e[i].u, e[i].v); solve(1, Q); for (int i=1; i<=Q; ++i) puts(ans[i] ? "Connected" : "Disconnected"); return 0; }
下面这份代码是我之前的思路,会T(废话)
# include <map> # include <stdio.h> # include <assert.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10, N = 1e6 + 10; const int mod = 1e9+7; # define RG register # define ST static int n, m; map< pair<int,int>, bool > mp; struct edge { int u, v; edge() {} edge(int u, int v) : u(u), v(v) {} inline void set() { scanf("%d%d", &u, &v); } }t[M], e[M]; struct quest { int c, u[5], v[5]; inline void set() { scanf("%d", &c); for (int i=1, t; i<=c; ++i) { scanf("%d", &t); u[i] = e[t].u, v[i] = e[t].v; } } }q[M]; int st[N], stn=0; struct us { int n, fa[M], rk[M]; inline void set(int _n) { n = _n; for (int i=1; i<=n; ++i) fa[i] = i, rk[i] = 1; } inline int getf(int x) { return fa[x] == x ? x : getf(fa[x]); } inline void un(int x, int y) { x = getf(x), y = getf(y); if(x == y) return; if(rk[x] > rk[y]) swap(x, y); if(rk[x] == rk[y]) ++rk[y], st[++stn] = -y; fa[x] = y; st[++stn] = x; -- n; } inline void re() { int x = st[stn]; --stn; if(x<0) -- rk[-x]; else fa[x] = x, ++ n; } }E; bool ans[M]; bool u[M]; inline void add(int u, int v) { mp[make_pair(u, v)] = 1; mp[make_pair(v, u)] = 1; } inline bool query(int u, int v) { return mp.find(make_pair(u, v)) == mp.end(); } inline void solve(int ql, int qr, int er) { int cur_stn = stn, tn = 0, ps; for (int i=ql; i<=qr; ++i) for (int j=1; j<=q[i].c; ++j) add(q[i].u[j], q[i].v[j]); for (int i=1; i<=er; ++i) if(u[i] = query(e[i].u, e[i].v)) E.un(e[i].u, e[i].v); mp.clear(); // printf("ql = %d, qr = %d, E.n = %d\n", ql, qr, E.n); if(E.n == 1) { for (int i=ql; i<=qr; ++i) ans[i] = 1; while(stn != cur_stn) E.re(); return ; } if(ql == qr) { while(stn != cur_stn) E.re(); return ; } for (int i=1; i<=er; ++i) if(!u[i]) t[++tn] = e[i]; ps = tn; for (int i=1; i<=er; ++i) if(u[i]) t[++tn] = e[i]; for (int i=1; i<=er; ++i) e[i] = t[i]; int qmid = ql + qr >> 1; solve(ql, qmid, ps); solve(qmid+1, qr, ps); while(stn != cur_stn) E.re(); } int main() { int en = 0; cin >> n >> m; E.set(n); for (int i=1; i<=m; ++i) e[i].set(); int Q; cin >> Q; for (int i=1; i<=Q; ++i) q[i].set(); solve(1, Q, m); for (int i=1; i<=Q; ++i) puts(ans[i] ? "Connected" : "Disconnected"); return 0; }