zoukankan      html  css  js  c++  java
  • [圆方树] Luogu P4630 Duathlon 铁人两项

    题目描述

    比特镇的路网由 mm 条双向道路连接的 nn 个交叉路口组成。

    最近,比特镇获得了一场铁人两项锦标赛的主办权。这场比赛共有两段赛程:选手先完成一段长跑赛程,然后骑自行车完成第二段赛程。

    比赛的路线要按照如下方法规划:

    1. 先选择三个两两互不相同的路口 s, cs,c和 ff,分别作为比赛的起点、切换点(运动员在长跑到达这个点后,骑自行车前往终点)、终点。
    2. 选择一条从 ss出发,经过 cc最终到达 ff的路径。考虑到安全因素,选择的路径经过同一个点至多一次。

    在规划路径之前,镇长想请你帮忙计算,总共有多少种不同的选取 s, cs,c和 ff的方案,使得在第 22步中至少能设计出一条满足要求的路径。

    题解

    • 把圆方树建出来,在树中任意枚举两个圆点作为s和f,然后考虑c有多少种选法。

    • 令每个圆点的权值为-1,每个方点的权值为点双大小,那么选法就是两点路径的权值和

    • 也就是说我们要求圆方树上n^2条圆点到圆点的路径的权值和,很容易想到计算每个点被算了多少次

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #define N 400010
     4 using namespace std;
     5 int n,m,tot,cnt,num,sum,head[N],last[N],stack[N],sz[N],val[N],dfn[N],low[N];
     6 long long ans;
     7 struct edge {int to,from;}e[N],E[N];
     8 void insert(int x,int y)
     9 {
    10     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt;
    11     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt;
    12 }
    13 void ins(int x,int y){ E[++num].to=y,E[num].from=last[x],last[x]=num; }
    14 void tarjan(int x)
    15 {
    16     dfn[x]=low[x]=++dfn[0],stack[++stack[0]]=x,sz[x]=1,val[x]=-1;
    17     for (int i=head[x],l;i;i=e[i].from)
    18         if (!dfn[e[i].to])
    19         {
    20             tarjan(e[i].to),low[x]=min(low[x],low[e[i].to]);
    21             if (low[e[i].to]>=dfn[x])
    22             {
    23                 ins(x,++tot),val[tot]=1,l=0;
    24                 do{ l=stack[stack[0]--],ins(tot,l),sz[tot]+=sz[l],++val[tot]; }while (l!=e[i].to);
    25                 sz[x]+=sz[tot];
    26             }
    27         }
    28         else low[x]=min(low[x],dfn[e[i].to]);
    29 }
    30 void dfs(int x)
    31 {
    32     if (x<=n) ans+=1ll*(sum-1)*val[x];
    33     ans+=1ll*(sum-sz[x])*sz[x]*val[x];
    34     for (int i=last[x];i;i=E[i].from) ans+=1ll*(sum-sz[E[i].to])*sz[E[i].to]*val[x],dfs(E[i].to); 
    35 }
    36 int main()
    37 {
    38     scanf("%d%d",&n,&m),tot=n;
    39     for (int x,y;m;m--) scanf("%d%d",&x,&y),insert(x,y);
    40     for (int i=1;i<=n;i++) if (!dfn[i]) tarjan(i),sum=sz[i],dfs(i);
    41     printf("%lld",ans);
    42  } 
  • 相关阅读:
    进度条
    html5 表单新增事件
    html5 表单的新增type属性
    html5 表单的新增元素
    html5 语义化标签
    jq 手风琴案例
    codeforces 702D D. Road to Post Office(数学)
    codeforces 702C C. Cellular Network(水题)
    codeforces 702B B. Powers of Two(水题)
    codeforces 702A A. Maximum Increase(水题)
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11281783.html
Copyright © 2011-2022 走看看