• 【BZOJ 2152】聪聪可可 点分治


    对于一棵树,fdrt找到重心,然后分治每个子树。

    在一棵以重心为根的树上,符合条件的链是:

      1.过重心(根)

      2.不过重心

    对于1我们只需dfs出距离重心(根)的距离然后统计再减去有重叠的边

    对于2我们只需递归处理子树,这样2就分为过子树的根(重心)的链和不过子树根(重心)的链······

    这就是点分治啦,貌似边分治更优,但是为了减少代码量,效率什么的我统统都不要(╬▔皿▔)

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define read(x) x=getint()
    using namespace std;
    const int N=20003;
    inline const int max( const int &a, const int &b) {return a>b?a:b;}
    inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
    struct node {
        int nxt, to, w;
    } E[N<<1];
    int point[N], size[N], ma[N], n, cnt=0, rt=0, ans=0, table[N], tn, di[N];
    bool vis[N];
    inline void insect( int x, int y, int z) {
        cnt++;
        E[cnt].nxt = point[x];
        E[cnt].to = y;
        E[cnt].w = z;
        point[x] = cnt;
    }
    inline void fdrt( int x, int fa, int s) {
        size[x] = 1;
        ma[x] = 0;
        for( int tmp = point[x]; tmp; tmp = E[tmp].nxt)
            if ( !vis[E[tmp].to] && E[tmp].to != fa) {
                fdrt( E[tmp].to, x, s);
                size[x] += size[E[tmp].to];
                ma[x] = max( ma[x], size[E[tmp].to]);
            }
        if ( s - ma[x] > ma[x])
            ma[x] = s - ma[x];
        if ( ma[x] < ma[rt])
            rt = x;
    }
    inline void mktb( int x, int fa) {
        table[ ++tn] = di[x];
        for( int tmp = point[x]; tmp; tmp = E[tmp].nxt)
            if ( !vis[E[tmp].to] && E[tmp].to != fa) {
                di[E[tmp].to] = di[x] + E[tmp].w;
                mktb( E[tmp].to, x);
            }
    }
    inline int work( int x, int beg) {
        int cn0 = 0, cn1 = 0, cn2 = 0;
        tn = 0;
        di[x] = beg;
        mktb( x, -1);
        for( int i = 1; i <= tn; ++i) {
            switch ( table[i] % 3) {
                case 0:
                    ++cn0;
                break;
                case 1:
                    ++cn1;
                break;
                case 2:
                    ++cn2;
                break;
            }
        }
        return cn0 * cn0 + ( ( cn1 * cn2) << 1);
    }
    inline void dfs( int x, int s) {
        vis[x] = 1;
        ans += work( x, 0);
        for( int tmp = point[x], ss; tmp; tmp = E[tmp].nxt)
            if ( !vis[E[tmp].to]) {
                ans -= work( E[tmp].to, E[tmp].w);
                if ( size[E[tmp].to] > size[x])
                    ss = s - size[x];
                else
                    ss = size[E[tmp].to];
                rt = 0;
                fdrt( E[tmp].to, x, ss);
                dfs( rt, ss);
            }
    }
    inline int gcd( int x, int y) {
        int r = x % y;
        while ( r) {
            x = y;
            y = r;
            r = x % y;
        }
        return y;
    }
    int main() {
        read( n);
        int u, v, e;
        for( int i = 1; i < n; ++i) {
            read( u);
            read( v);
            read( e);
            e %= 3;
            insect( u, v, e);
            insect( v, u, e);
        }
        ma[0] = n+3;
        memset( vis, 0, sizeof(vis));
        fdrt( (n+1)>>1, -1, n);
        dfs( rt, n);
        int m = n * n, tong = gcd( ans, m);
        printf( "%d/%d
    ", ans / tong, m / tong);
        return 0;
    }
    

    点分治完成啦,找重心估计s时偷了点懒效率立刻就低了∑(っ °Д °;)っ还是改回来了

    还有我的码风这次有点奇怪⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄.是不是不再像以前那么挤了ヾ (o ° ω ° O ) ノ゙

  • 相关阅读:
    (转)ASP.NET Mvc 2.0 1. Areas的创建与执行
    新世代交易管理機制~System.Transactions
    水晶報表入門
    MyGeneration 如何连接 mysql 来生成代码
    vs.net 启动不了
    Oracle面试问题-技术篇
    把excel两列字符数据用逗号合并起来
    论Leader的技能
    物流行业名词
    html 向aspx 页面传值
  • 原文地址:https://www.cnblogs.com/abclzr/p/5313322.html
Copyright © 2020-2023  润新知