zoukankan      html  css  js  c++  java
  • Solution -「LOCAL」画画图

    (mathcal{Description})

      OurTeam.

      给定一棵 (n) 个点的树形随机的带边权树,求所有含奇数条边的路径中位数之和。树形生成方式为随机取不连通两点连边直到全部连通。

      (nle32000)

    (mathcal{Solution})

      考虑用中位数的标准姿势统计每条边的贡献——小于它的设为 (-1),大于它的设为 (+1),边权相等按编钦定大小关系。那么这条边的贡献就是路径两端权值加和为 (0) 的路径对数(显然每对路径连起来都是奇数路径)。

      令 (f(u,i)) 表示 (u) 子树内到 (u) 路径权值和为 (i) 的结点数量。对于一条边 ((u,v)),不妨设 (u)(v) 的父亲,设我们已经得到了全树的 DP 信息,考虑到题目中随机树的期望深度为 (mathcal O(sqrt n)),所以暴力爬树统计 (v) 子树内和 (v) 子树外的信息即可求到当前答案。顺序枚举边,每条边仅会由 (+1) 变为 (-1),所以暴力仍然暴力爬树修改 DP 信息即可。实现上,利用树深限制,拿一个内存池储存 DP 信息;爬树统计时限制可能贡献答案的权值区间即可通过本题。

      复杂度 (mathcal O(n^2)),不过可以算出带一个 (frac{1}6) 的常数,所以可过。

    (mathcal{Code})

      这里以直径中点作为根(为了和某毒瘤比赛卡常),不过随便选一个根都是可过的。

    #include <queue>
    #include <cstdio>
    #include <cstring>
    
    typedef long long LL;
    
    const int MAXN = 32000, MAXSQRT = 180, MAXV = 1e6;
    int n, ecnt, head[MAXN + 5], fa[MAXN + 5], dep[MAXN + 5], faw[MAXN + 5];
    int mempool[MAXN * MAXSQRT * 2], *f[MAXN + 5], *frepos = mempool, *g;
    int pre[MAXN + 5], buc[MAXV + 5], ori[MAXN + 5], down[MAXN + 5];
    
    struct Edge { int to, cst, nxt; } graph[MAXN * 2 + 5];
    struct EdgeSet { int u, v, w; } eset[MAXN + 5];
    
    inline int rint () {
    	int x = 0; char s = getchar ();
    	for ( ; s < '0' || '9' < s; s = getchar () );
    	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
    	return x;
    }
    
    inline int min_ ( const int a, const int b ) { return a < b ? a : b; }
    inline int max_ ( const int a, const int b ) { return a < b ? b : a; }
    
    inline void link ( const int s, const int t, const int c ) {
    	graph[++ ecnt] = { t, c, head[s] };
    	head[s] = ecnt;
    }
    
    inline void BFS ( const int s ) {
    	static std::queue<int> que;
    	que.push ( s ); dep[s] = 1;
    	while ( ! que.empty () ) {
    		int u = que.front (); que.pop ();
    		for ( int i = head[u], v; i; i = graph[i].nxt ) {
    			if ( ! dep[v = graph[i].to] ) {
    				pre[v] = u, dep[v] = dep[u] + 1;
    				que.push ( v );
    			}
    		}
    	}
    }
    
    inline void init ( const int u ) {
    	dep[u] = 0;
    	for ( int i = head[u], v; i; i = graph[i].nxt ) {
    		if ( ( v = graph[i].to ) ^ fa[u] ) {
    			fa[v] = u, faw[v] = 1, down[graph[i].cst] = v, init ( v );
    			if ( dep[v] + 1 > dep[u] ) dep[u] = dep[v] + 1;
    		}
    	}
    	f[u] = frepos += dep[u] + 1, frepos += dep[u] + 1;
    }
    
    inline void DP ( const int u ) {
    	*f[u] = 1;
    	for ( int i = head[u], v; i; i = graph[i].nxt ) {
    		if ( ( v = graph[i].to ) ^ fa[u] ) {
    			DP ( v );
    			for ( int j = -dep[v]; j <= dep[v]; ++ j ) f[u][j + 1] += f[v][j];
    		}
    	}
    }
    
    inline LL update ( const int s ) {
    	int l = -dep[s], r = dep[s]; faw[s] = -1;
    	for ( int u = fa[s], v = s, d1 = 0, d2 = 0; u; u = fa[v = u] ) {
    		d1 += v ^ s ? faw[v] : 1, d2 += faw[v];
    		for ( int i = -dep[s]; i <= dep[s]; ++ i ) {
    			f[u][i + d1] -= f[s][i];
    			f[u][i + d2] += f[s][i];
    		}
    		for ( int i = max_ ( -dep[u], l ), t = min_ ( dep[u], r ), d = d2 + 1; i <= t; ++ i ) {
    			g[i + d] += f[u][i] - f[v][i - faw[v]];
    		}
    		l -= faw[u], r -= faw[u];
    	}
    	LL ret = 0;
    	for ( int i = -dep[s]; i <= dep[s]; ++ i ) {
    		ret += 1ll * f[s][i] * g[-i];
    		g[-i] = 0;
    	}
    	return ret;
    }
    
    int main () {
    	n = rint (); int mxw = 0;
    	for ( int i = 1, u, v, w; i < n; ++ i ) {
    		u = rint (), v = rint (), w = rint ();
    		eset[i] = { u, v, w }, ++ buc[w];
    		if ( w > mxw ) mxw = w;
    	}
    	for ( int i = 2; i <= mxw; ++ i ) buc[i] += buc[i - 1];
    	for ( int i = 1; i < n; ++ i ) {
    		eset[i].w = buc[ori[buc[eset[i].w]] = eset[i].w] --;
    		link ( eset[i].u, eset[i].v, eset[i].w );
    		link ( eset[i].v, eset[i].u, eset[i].w );
    	}
    	BFS ( 1 );
    	int s = 0, t = 0;
    	for ( int i = 1; i <= n; ++ i ) {
    		if ( dep[i] > dep[s] ) s = i;
    		dep[i] = pre[i] = 0;
    	}
    	BFS ( s );
    	for ( int i = 1; i <= n; ++ i ) if ( dep[i] > dep[t] ) t = i;
    	for ( int i = dep[s] + dep[t] - 2 >> 1; i --; t = pre[t] );
    	init ( t ), DP ( t );
    	g = frepos += dep[t] + 1, frepos += dep[t] + 1;
    	LL ans = 0;
    	for ( int i = 1; i < n; ++ i ) ans += ori[i] * update ( down[i] );
    	printf ( "%lld
    ", ans );
    	return 0;
    }
    
  • 相关阅读:
    PHP基础函数、自定义函数以及数组
    php 中 isset 和empty 的区别
    mysql中索引的使用
    mysql 中的增改查删(CRUD)
    mysql语句应该注意的问题
    《zw版·Halcon-delphi系列原创教程》 水果自动分类脚本(机器学习、人工智能)
    《zw版·Halcon-delphi系列原创教程》 2d照片-3d逆向建模脚本
    《zw版·Halcon-delphi系列原创教程》简单的令人发指,只有10行代码的车牌识别脚本
    《zw版·Halcon-delphi系列原创教程》航母舰载机·视觉定位标志的识别代码
    zw版_zw中文增强版Halcon官方Delphi例程
  • 原文地址:https://www.cnblogs.com/rainybunny/p/13498417.html
Copyright © 2011-2022 走看看