zoukankan      html  css  js  c++  java
  • BZOJ 3451Normal (点分治+FFT)

    题意

    BZOJ3451

    题解

    Orz yyb题解

    CODE

    #pragma GCC optimize ("O2")
    #include <bits/stdc++.h>
    using namespace std;
    const double Pi = acos(-1.0);
    const int MAXN = 30005;
    
    int fir[MAXN], to[MAXN<<1], nxt[MAXN<<1], cnt;
    inline void link(int u, int v) {
    	to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
    	to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
    }
    bool ban[MAXN];
    int Get_Size(int u, int ff) {
    	int re = 1;
    	for(int i = fir[u]; i; i = nxt[i])
    		if(to[i] != ff && !ban[to[i]])
    			re += Get_Size(to[i], u);
    	return re;
    }
    inline int Get_G(int u, int ff, int Size, int &g) {
    	int re = 1; bool flg = 1;
    	for(int i = fir[u]; i; i = nxt[i])
    		if(to[i] != ff && !ban[to[i]]) {
    			int tmp = Get_G(to[i], u, Size, g); re += tmp;
    			if(tmp<<1 > Size) flg = 0;
    		}
    	if((Size-re)<<1 > Size) flg = 0;
    	if(flg) g = u; return re;
    }
    const int MAX = 70000;
    struct cp {
    	double x, y; cp(){} cp(double x, double y):x(x), y(y){}
    	inline cp operator +(const cp &o)const { return cp(x + o.x, y + o.y); }
    	inline cp operator -(const cp &o)const { return cp(x - o.x, y - o.y); }
    	inline cp operator *(const cp &o)const { return cp(x*o.x-y*o.y, x*o.y+y*o.x); }
    }A[MAX], B[MAX], W[MAX];
    int rv[MAX];
    inline void FFT(cp *a, int N, int flg) {
    	for(int i = 0; i < N; ++i) if(rv[i] < i) swap(a[rv[i]], a[i]);
    	cp u, v, w;
    	for(int i = 2; i <= N; i<<=1)
    		for(int j = 0; j < N; j += i)
    			for(int k = j; k < j+i/2; ++k) {
    				w = W[N/i*(k-j)]; w.y *= flg;
    				u = a[k], v = a[k+i/2] * w;
    				a[k] = u + v;
    				a[k+i/2] = u - v;
    			}
    	if(flg == -1) for(int i = 0; i < N; ++i) a[i].x /= N;
    }
    inline void Mul(int *a, int *b, int n, int m, int *c) {
    	int N, lg = 0; for(N = 1; N <= (n+m); ++lg, N<<=1);
    	for(int i = 0; i < N; ++i) rv[i] = (rv[i>>1]>>1) | ((i&1)<<(lg-1));
    	for(int i = 2; i <= N; i<<=1)
    		for(int k = 0; k < i/2; ++k)
    			W[N/i*k] = cp(cos(2*Pi/i*k), sin(2*Pi/i*k));
    	for(int i = 0; i <= n; ++i) A[i].x = a[i];
    	for(int i = 0; i <= m; ++i) B[i].x = b[i];
    	FFT(A, N, 1), FFT(B, N, 1);
    	for(int i = 0; i < N; ++i) A[i] = A[i] * B[i];
    	FFT(A, N, -1);
    	for(int i = 0; i <= n+m; ++i) c[i] = int(round(A[i].x));
    	for(int i = 0; i < N; ++i) A[i] = B[i] = cp(0, 0);
    }
    int a[MAXN], b[MAXN], c[MAXN], la, lb, Ans[MAXN];
    void dfs(int u, int ff, int d) {
    	++b[d]; lb = max(lb, d);
    	for(int i = fir[u]; i; i = nxt[i])
    		if(to[i] != ff && !ban[to[i]])
    			dfs(to[i], u, d+1);
    }
    void TDC(int u) {
    	int Size = Get_Size(u, 0);
    	Get_G(u, 0, Size, u);
    	la = 0; a[0] = 1;
    	for(int i = fir[u]; i; i = nxt[i])
    		if(!ban[to[i]]) {
    			lb = 0; dfs(to[i], u, 1);
    			Mul(a, b, la, lb, c);
    			for(int i = 0; i <= la+lb; ++i) Ans[i] += c[i], c[i] = 0;
    			for(int i = 0; i <= lb; ++i) a[i] += b[i], b[i] = 0;
    			la = max(la, lb);
    		}
    	for(int i = 0; i <= la; ++i) a[i] = 0;
    	ban[u] = 1;
    	for(int i = fir[u]; i; i = nxt[i])
    		if(!ban[to[i]]) TDC(to[i]);
    }
    int n;
    int main () {
        scanf("%d", &n);
    	for(int i = 1, x, y; i < n; ++i)
    		scanf("%d%d", &x, &y), link(x+1, y+1);
    	TDC(1);
    	double ans = n;
    	for(int i = 1; i <= n; ++i) ans += 2.0 * Ans[i] / (i+1);
    	printf("%.4f
    ", ans);
    }
    

    看似十分正常而且420ms过了美滋滋。但是实际上最坏情况是O(n2logn)O(n^2logn)。可以发现我们点分治算答案的时候每一次的复杂度都与前面子树的最大深度也就是代码中的la。这样下来如果第一个子树深度为O(n)O(n),每次都是O(nlogn)O(nlogn)的,所以就O(n2logn)O(n^2logn)了。

    正确写法是把所有子树的多项式和的平方后减去平方的和,就是两两乘积的和了。

    还有一种就是点分治时把儿子按深度排个序,然后每次每棵子树的时间复杂度只跟自己深度有关(因为前面的深度都小于等于自己的深度),然后深度小于等于子树大小。如果是子树大小的时间复杂度则容易证明是O(nlogn)O(nlogn)的。总时间复杂度就是O(nlog2n)O(nlog^2n)

  • 相关阅读:
    实验二
    2
    DS博客作业08--课程总结
    DS博客作业07--查找
    DS博客作业06--图
    DS博客园作业05--树
    有向图强连通分量Tarjan算法
    nyoj 题目737 合并石子(一)
    nyoj 题目61 传纸条
    nyoj 题目49 开心的小明
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039232.html
Copyright © 2011-2022 走看看