zoukankan      html  css  js  c++  java
  • [APIO2018]铁人两项 --- 圆方树

     [APIO2018] 铁人两项

     

    题目大意:

    给定一张图,问有多少三元组(a,b,c)(a,b,c 互不相等)满足存在一条点不重复的以a为起点,经过b,终点为c的路径

     

    如果你不会圆方树 ----------------------- 放弃是最好的选择(先学了再来吧)

    如果你会圆方树

    考虑((a,...,c))

    1.如果a,c不同属一个点双,不难发现答案为路上经过的(点双的节点个数)的和减去割点数

    2.如果a,c同属一个点双,那么答案为本点双的节点个数 - 2

    自然地想到方点的权值为内含节点个数(割点算在内),圆点权值为 -1

     

    所以答案就是树上的路径权值之和了。

    树形DP一下就好了 ------------------------------------------- 那就是错了。。。。

     

    考虑的三元组中的a,c明显指圆点,方点是不能作为路径的起点和终点的。。。。。

    于是,考虑每个点能出现的路径个数。

    记(sz[e])表示节点e在圆方树的子树中存在多少圆点

    对于每个点,存在两种路径:

    分两种情况统计即可

    额外的,对于圆点,因为可能作为起点,终点,还要额外统计

    莫名其妙的$loj$和$luogu$的$rk1$.......还是挺懵逼的

     

    代码如下:

    #include <cstdio>
    #define sid 500050
    using namespace std;
    
    long long ans;
    int n, m, top, tim, nt, cnt, Asz, pp;
    int dfn[sid], low[sid], st[sid], sz[sid], val[sid];
    int cap[sid], acap[sid], nxt[sid], node[sid];
    
    int read() { scanf("%d", &pp); return pp; }
    void upmin(int &a, int b) { if(a > b) a = b; }
    void Add(int u, int v) { nxt[++ cnt] = cap[u]; cap[u] = cnt; node[cnt] = v; }
    void Bdd(int u, int v) { nxt[++ cnt] = acap[u]; acap[u] = cnt; node[cnt] = v; }
    
    void Tarjan(int e) {
        dfn[e] = low[e] = ++ tim;
        st[++ top] = e; sz[e] = 1; val[e] = -1;
        for(int i = acap[e], d; i; i = nxt[i])
        if(!dfn[d = node[i]]) {
            Tarjan(d); upmin(low[e], low[d]);
            if(low[d] < dfn[e]) continue;
            int p; ++ nt; Add(e, nt);
            do {
                p = st[top --]; val[nt] ++;
                Add(nt, p); sz[nt] += sz[p];
            } while(p != d);
            val[nt] ++; sz[e] += sz[nt];
        }
        else upmin(low[e], dfn[d]);
    }
    
    void DP(int e) {
        if(e <= n) ans += 1ll * (Asz - 1) * val[e];
        ans += 1ll * (Asz - sz[e]) * sz[e] * val[e];
        for(int i = cap[e]; i; i = nxt[i]) {
            int d = node[i];
            DP(d), ans += 1ll * (Asz - sz[d]) * sz[d] * val[e];
        }
    }
    
    int main() {
        nt = n = read(); m = read();
        for(int i = 1; i <= m; i ++) {
            int u = read(), v = read();
            Bdd(u, v); Bdd(v, u);
        }
        for(int i = 1; i <= n; i ++)
        if(!dfn[i])
        Tarjan(i), Asz = sz[i], DP(i);
        printf("%lld
    ", ans);
        return 0;
    }

     

     

     

  • 相关阅读:
    Minimum Path Sum,最短路径问题,动态规划
    UniquePaths,UniquePaths2,路径问题。动态规划。
    LengthOfLastWord,字符串最后一个子串的长度
    间隔问题,合并间隔(merge interval),插入间隔(insert interval)
    矩阵螺旋遍历Spiral Matrix,Spiral Matrix2
    Centos 5.2 下配置 php 的 json 扩展
    一个睡五分钟等于六个钟头的方法
    js div 排除内部的点击事件 就是 冒泡的处理
    做微信开发 “人脉圈的” 总结
    YII 学习笔记
  • 原文地址:https://www.cnblogs.com/reverymoon/p/9102144.html
Copyright © 2011-2022 走看看