• [做题记录-乱做]Luogu3687 [ZJOI2017]仙人掌


    题意

    给你张无自环无重边的无向连通图, 求有多少种方案加边使得这个图是仙人掌。
    (n leq 5 imes 10^5)

    题解

    牛逼题。
    考虑这么搞, 把环上的边断掉因为环上的边肯定没用。然后问题转化到树上, 把所有树的答案乘起来就是答案。
    按照套路设(f_x)表示(x)子树内没有向上的边的方案数, (g_x)表示(x)子树内有向上的边的方案数。
    如果直接转移, 那么在考虑一个点(x)的儿子的时候, 每条边都不知道是不选还是选, 选出来也不知道如何去配对, 那么配对的时候需要求一个数组(h)表示这么多个点合并起来的方案数, 同时还要使用多项式, 对每个点构造一个多项式(gx + f)然后分治(FFT)求出系数。然后就(n log_2^2 n)了。
    但是这里有一个很神奇的转化, 让不被覆盖的边看成自己被覆盖, 那么问题变成了要求每条边都被覆盖。这个问题的话你发现每个儿子必须有边延伸出来, 然后你可以在每个点直接考虑儿子的情况。
    具体来说有下面的转移:

    [h_i = h_{i - 1} + h_{i - 2} (i - 1) \ f_x = h_{dx}prod_{y in son_x}g_y \ g_x = prod_{y in son_x}h_{dx} + sum_{y in son_x}g_y imes prod_{z in son_x, z eq y} g_zh_{dx - 1} =prod_{y in son_x}g_yh_{dx + 1}]

    (h)就是用来配对的那个数组。
    然后问题就在于判断仙人掌了, 这个可以直接(dfs + stack), 注意判断是否进入环的时候用(dfn)不要用(vis)

    /*
    	QiuQiu /qq
      ____    _           _                 __                
      / __   (_)         | |               / /                
     | |  | |  _   _   _  | |  _   _       / /    __ _    __ _ 
     | |  | | | | | | | | | | | | | |     / /    / _` |  / _` |
     | |__| | | | | |_| | | | | |_| |    / /    | (_| | | (_| |
      \___\_ |_|  \__,_| |_|  \__, |   /_/      \__, |  \__, |
                                __/ |               | |     | |
                               |___/                |_|     |_|
    */
    
    #include <bits/stdc++.h>
    
    using namespace std;
    
    class Input {
    	#define MX 1000000
    	private :
    		char buf[MX], *p1 = buf, *p2 = buf;
    		inline char gc() {
    			if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MX, stdin);
    			return p1 == p2 ? EOF : *(p1 ++);
    		}
    	public :
    		Input() {
    			#ifdef Open_File
    				freopen("a.in", "r", stdin);
    				freopen("a.out", "w", stdout);
    			#endif
    		}
    		template <typename T>
    		inline Input& operator >>(T &x) {
    			x = 0; int f = 1; char a = gc();
    			for(; ! isdigit(a); a = gc()) if(a == '-') f = -1;
    			for(; isdigit(a); a = gc()) 
    				x = x * 10 + a - '0';
    			x *= f;
    			return *this;
    		}
    		inline Input& operator >>(char &ch) {
    			while(1) {
    				ch = gc();
    				if(ch != '
    ' && ch != ' ') return *this;
    			}
    		}
    		inline Input& operator >>(char *s) {
    			int p = 0;
    			while(1) {
    				s[p] = gc();
    				if(s[p] == '
    ' || s[p] == ' ' || s[p] == EOF) break;
    				p ++; 
    			}
    			s[p] = '';
    			return *this;
    		}
    	#undef MX
    } Fin;
    
    class Output {
    	#define MX 1000000
    	private :
    		char ouf[MX], *p1 = ouf, *p2 = ouf;
    		char Of[105], *o1 = Of, *o2 = Of;
    		void flush() { fwrite(ouf, 1, p2 - p1, stdout); p2 = p1; }
    		inline void pc(char ch) {
    			* (p2 ++) = ch;
    			if(p2 == p1 + MX) flush();
    		}
    	public :
    		template <typename T> 
    		inline Output& operator << (T n) {
    			if(n < 0) pc('-'), n = -n;
    			if(n == 0) pc('0');
    			while(n) *(o1 ++) = (n % 10) ^ 48, n /= 10;
    			while(o1 != o2) pc(* (--o1));
    			return *this; 
    		}
    		inline Output & operator << (char ch) {
    			pc(ch); return *this; 
    		}
    		inline Output & operator <<(const char *ch) {
    			const char *p = ch;
    			while( *p != '' ) pc(* p ++);
    			return * this;
    		}
    		~Output() { flush(); } 
    	#undef MX
    } Fout;
    
    #define cin Fin
    #define cout Fout
    #define endl '
    '
    
    using LL = long long;
    using pii = pair<int, int>;
    
    const int P = 998244353;
    
    inline int Mod(int x) { return x + ((x >> 31) & P); }
    inline void pls(int &x, int v) { x = Mod(x + v - P); }
    inline void dec(int &x, int v) { x = Mod(x - v); }
    
    const int N = 5e5 + 10;
    
    int n, m;
    struct edge {
    	int to, next;
    } e[N * 4];
    int cnt = 1, head[N];
    int stk[N * 2], top;
    int bj[N * 4], vis[N * 2];
    
    void push(int x, int y) {
    	e[++ cnt] = (edge) {y, head[x]}; head[x] = cnt;
    }
    int dfn[N];
    void clr() {
    	for(int i = 1; i <= cnt; i ++) bj[i] = dfn[i] = 0;
    	cnt = 1; for(int i = 1; i <= n; i ++) head[i] = 0, vis[i] = 0;
    }
    
    bool flg;
    
    inline void addtag(int i) { bj[i] ++; bj[i ^ 1] ++; if(bj[i] > 1) { cout << 0 << endl; flg = 1; } }
    
    void dfs1(int x, int fx) {
    	//cerr << x << endl;
    	dfn[x] = ++ dfn[0];
    	vis[x] = 1; if(flg) return ;
    	for(int i = head[x]; i; i = e[i].next) {
    		int y = e[i].to; if(y == fx) continue;
    		if(! vis[y]) {
    			stk[++ top] = i; dfs1(y, x); if(flg) return ; top --;
    		}
    		else if(dfn[y] < dfn[x]) {
    			//cerr << "Case" << endl;
    			//cerr << x << endl;
    			addtag(i); if(flg) return ; 
    			for(int j = top; j >= 1; j --) {
    				int p = stk[j];
    				int now = e[p].to;
    				addtag(p); if(flg) return ;
    				if(e[p ^ 1].to == y) break;
    			}
    			
    		}
    	}
    }
    
    int f[N], g[N], h[N];
    
    void dfs2(int x, int fx) {
    	vis[x] = 1;
    	f[x] = 1; g[x] = 0; int dx = 0;
    	for(int i = head[x]; i; i = e[i].next) if(! bj[i]) {
    		int y = e[i].to; if(y == fx) continue; 
    		dfs2(y, x); dx ++;
    		f[x] = 1ll * f[x] * g[y] % P;
    	}
    	g[x] = 1ll * f[x] * h[dx + 1] % P;
    	f[x] = 1ll * h[dx] * f[x] % P; 
    }
    
    void solve() {
    	cin >> n >> m; flg = 0; top = 0;
    	for(int i = 1, x, y; i <= m; i ++) {
    		cin >> x >> y;
    		push(x, y); push(y, x);
    	}
    	dfs1(1, 0);
    	if(flg) {// cerr << 312 << endl;
    		clr(); return ;
    	}
    	for(int i = 1; i <= n; i ++) vis[i] = 0;
    	h[0] = 1; h[1] = 1;
    	for(int i = 2; i <= n; i ++) h[i] = (h[i - 1] + 1ll * h[i - 2] * (i - 1) % P) % P;
    	int ans = 1;
    	for(int i = 1; i <= n; i ++) if(! vis[i]) {
    		dfs2(i, 0);
    		ans = 1ll * ans * f[i] % P;
    	}
    	cout << ans << endl;
    	clr();
    }
    
    int main() {
    	int Case; cin >> Case;
    	while(Case --) solve();
    	return 0;
    }
    
  • 相关阅读:
    清除富文本样式
    jquery--cookie应用
    Log4j 配置详解
    判断请求是否为ajax
    日期工具类
    Windows Server2012 KB2919355 补丁无法安装
    安装系统步骤:
    大白菜u盘启动盘制作工具取消赞助商方法详解
    视频使用教程
    检查网络是否正常的几种命令
  • 原文地址:https://www.cnblogs.com/clover4/p/15333930.html
Copyright © 2020-2023  润新知