• 「HAOI2018」反色游戏(找性质+tarjan求割点)


    https://loj.ac/problem/2524

    类似于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("
    ")
    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;
    	}
    }
    
  • 相关阅读:
    spring源码下载
    java资料共享
    《Linux命令行与shell脚本编程大全》读书笔记
    《微服务设计》读书笔记
    tornado关于AsyncHTTPClient的使用笔记
    java stackoverflowerror与outofmemoryerror区别(转)
    JAVA关于泛型的笔记
    在JAVA中返回类型使用泛型T和Object有什么区别?
    《构架师的12项修炼》读书笔记
    关于控制台输入的代码怎么跑单元测试的问题记录
  • 原文地址:https://www.cnblogs.com/coldchair/p/12719130.html
Copyright © 2020-2023  润新知