「HAOI2018」反色游戏(找性质+tarjan求割点)
作者:互联网
类似于NOI ONline T1,
对于一棵树,不难发现,当黑点个数为奇数时,一定无解,为偶数时,一定可以调整出唯一一组解。
如果额外加一些非树边,那么不管非树边怎么选,树边都有办法调整,所以方案数是\(2^{非树边数}\)
考虑删掉一个点时,也就是看删掉这个点之后新形成的联通块有多少个,有没有联通块有奇数个黑点。
如果知道tarjan求割点的方法,不难得到以下解法:
对于一个联通块,随便选一个点作为根开始tarjan。
对于根,如果删掉它,它的dfs树上的每个子树会形成一个联通块。
对于dfs树上非根的点\(x\),如果删掉它,那些\(low[y]\ge dfn[x]\)的子节点\(y\)的子树会形成一个联通块,然后剩下的所有点会形成一个联通块。
这样我们只要tarjan一遍,顺便维护一些信息(子树黑点个数,会独立的子树的信息),就可以得到答案了。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i < _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int mo = 1e9 + 7;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
const int N = 2e5 + 5;
int T;
int n, m, x, y, r[N];
int fi[N], to[N * 2], nt[N * 2], tot = 1;
char str[N]; int a[N];
void link(int x, int y) {
nt[++ tot] = fi[x], to[tot] = y, fi[x] = tot;
}
int low[N], dfn[N], dfn0;
void cl() {
fo(i, 1, n) r[i] = fi[i] = low[i] = dfn[i] = 0;
tot = 1;
}
int s[N], cnt[N][2], bz[N], G;
void dg(int x, int la) {
bz[x] = G;
low[x] = dfn[x] = ++ dfn0;
s[x] = a[x];
cnt[x][0] = cnt[x][1] = 0;
for(int i = fi[x]; i; i = nt[i]) if(i != la) {
int y = to[i];
if(!dfn[y]) {
dg(y, i ^ 1);
s[x] ^= s[y];
low[x] = min(low[x], low[y]);
if(low[y] >= dfn[x]) {
cnt[x][s[y]] ++;
}
} else low[x] = min(low[x], dfn[y]);
}
}
int ltk;
void work() {
scanf("%d %d", &n, &m);
fo(i, 1, m) {
scanf("%d %d", &x, &y);
link(x, y); link(y, x);
r[x] ++, r[y] ++;
}
scanf("%s", str + 1);
fo(i, 1, n) a[i] = str[i] - '0';
ltk = 0;
fo(i, 1, n) if(!dfn[i]) {
ltk ++;
G = i, dg(i, 0);
}
}
int main() {
scanf("%d", &T);
fo(ii, 1, T) {
cl();
work();
int c1 = 0;
fo(i, 1, n) if(bz[i] == i)
c1 += (s[i] == 1);
int c = m - n + ltk;
pp("%lld ", c1 > 0 ? 0 : ksm(2, c));
fo(i, 1, n) {
if(!r[i]) {
pp("%lld ", c1 > 0 ? 0 : ksm(2, c));
} else {
if(!cnt[i][1] && (c1 - s[bz[i]]) == 0 && (s[bz[i]] ^ a[i]) == 0) {
pp("%lld ", ksm(2, c - r[i] + 1 + cnt[i][0] - (bz[i] == i)));
} else pp("0 ");
}
}
hh;
}
}
标签:tarjan,求割点,int,cnt,dfn,low,反色,bz,fo 来源: https://www.cnblogs.com/coldchair/p/12719130.html