zoukankan      html  css  js  c++  java
  • JZOJ 1967.【2011集训队出题】聪聪可可

    题目

    【2011集训队出题】聪聪可可

    思路

    看看做做 阴阳 这道题
    极力推荐
    自从做了这道题后,这些题就变成秒切的题了

    很容易想到求节点到分治中心的距离,然后 (mod 3)
    那么在求根节点一棵子树的答案时直接加上 (dis[(3-x) mod 3]) 的个数
    用个桶 (buc) 来记录,若当前节点的 (dis mod 3) 后结果为 (0),说明它到跟也为合法路径,此时 (res) 要额外 (+1)
    统计完一个子树的贡献后再将子树的信息加入桶中
    统计完所有子树,重新选根前再 (dfs) 一遍清除 (buc)

    (Code)

    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    const int N = 2e4 + 5;
    int n , h[N] , tot , size , siz[N] , son[N] , dis[N] , use[N] , ans , rt , buc[5];
    
    struct edge{
    	int to , nxt , w;
    }e[N * 2];
    
    inline void add(int x , int y , int z)
    {
    	e[++tot].to = y;
    	e[tot].w = z;
    	e[tot].nxt = h[x];
    	h[x] = tot;
    }
    
    inline void getrt(int x , int fa)
    {
    	son[x] = 0 , siz[x] = 1;
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == fa || use[v]) continue;
    		getrt(v , x);
    		siz[x] += siz[v];
    		son[x] = max(son[x] , siz[v]);
    	}
    	son[x] = max(son[x] , size - siz[x]);
    	rt = son[x] < son[rt] ? x : rt;
    }
    
    inline void getdis(int x , int fa)
    {
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == fa || use[v]) continue;
    		dis[v] = (dis[x] + e[i].w) % 3;
    		getdis(v , x);
    	}
    }
    
    inline int dfs(int x , int fa)
    {
    	int res = 0;
    	res += buc[(3 - dis[x]) % 3] + (dis[x] == 0 ? 1 : 0);
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == fa || use[v]) continue;
    		res += dfs(v , x);
    	}
    	return res;
    }
    
    inline void fill(int x , int fa)
    {
    	buc[dis[x]]++;
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == fa || use[v]) continue;
    		fill(v , x);
    	}
    }
    
    inline void clear(int x , int fa)
    {
    	buc[dis[x]]--;
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (v == fa || use[v]) continue;
    		clear(v , x);
    	}
    	dis[x] = 0;
    }
    
    inline int calc(int x)
    {
    	dis[x] = 0;
    	getdis(x , 0);
    	int res = 0;
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (use[v]) continue;
    		res += dfs(v , x) , fill(v , x);
    	}
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (use[v]) continue;
    		clear(v , x);
    	}
    	return res;
    }
    
    inline void divide(int x)
    {
    	use[x] = 1 , ans += calc(x);
    	for(register int i = h[x]; i; i = e[i].nxt)
    	{
    		int v = e[i].to;
    		if (use[v]) continue;
    		size = siz[v] , rt = 0;
    		getrt(v , x) , divide(rt);
    	}
    }
    
    inline int gcd(int a , int b){return b == 0 ? a : gcd(b , a % b);}
    
    int main()
    {
    	scanf("%d" , &n);
    	int u , v , w;
    	for(register int i = 1; i < n; i++) 
    	{
    		scanf("%d%d%d" , &u , &v , &w);
    		add(u , v , w) , add(v , u , w);
    	}
    	son[0] = 2e9 , size = n , rt = 0;
    	getrt(1 , 0) , divide(rt);
    	ans = ans * 2 + n;
    	int tmp = n * n , d = gcd(ans , tmp);
    	printf("%d/%d" , ans / d , tmp / d);
    }
    
  • 相关阅读:
    一道看似简单的sql需求却难倒各路高手
    手把手教你Linux服务器集群部署.net网站
    最简单的 Web Service 入门 (看了包会)
    360wifi 在 windows server 2008 / 2003 的使用方法
    react 入门
    bind、call、apply的区别
    webkit css 扩展
    如何构建一个微型的CMD模块化加载器
    Base64的原理、实现及应用
    You don't know JS 读书笔记(一)
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/13411854.html
Copyright © 2011-2022 走看看