【刷题】LOJ 2587 「APIO2018」铁人两项

题目描述

比特镇的路网由 \(m\) 条双向道路连接的 \(n\) 个交叉路口组成。

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

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

1、先选择三个两两互不相同的路口 \(s\)\(c\)\(f\) ,分别作为比赛的起点、切换点(运动员在长跑到达这个点后,骑自行车前往终点)、终点。

2、选择一条从 \(s\) 出发,经过 \(c\) 最终到达 \(f\) 的路径。考虑到安全因素,选择的路径经过同一个点至多一次。

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

输入格式

第一行包含两个整数 \(n\)\(m\) ,分别表示交叉路口和双向道路的数量。

接下来 \(m\) 行,每行两个整数 \(v_i\) ​​,\(u_i\) 。表示存在一条双向道路连接交叉路口 \(v_i\)\(u_i\) (\(1 \le v_i, u_i \le n, v_i \neq u_i\))。

保证任意两个交叉路口之间,至多被一条双向道路直接连接。

输出格式

输出一行,包括一个整数,表示能满足要求的不同的选取 \(s\)\(c\)\(f\) 的方案数。

样例

样例输入1

4 3
1 2
2 3
3 4

样例输出1

8

样例解释1

在第一个样例中,有以下 8 种不同的选择 \((s, c, f)\) 的方案:\((1, 2, 3)\)\((1, 2, 4)\)\((1, 3, 4)\)\((2, 3, 4)\)\((3, 2, 1)\)\((4, 2, 1)\)\((4, 3, 1)\)\((4, 3, 2)\)

样例输入2

4 4
1 2
2 3
3 4
4 2

样例输出2

14

样例解释2

在第二个样例中,有以下 14 种不同的选择 \((s, c, f)\) 的方案:\((1, 2, 3)\)\((1, 2, 4)\)\((1, 3, 4)\)\((1, 4, 3)\)\((2, 3, 4)\)\((2, 4, 3)\)\((3, 2, 1)\)\((3, 2, 4)\)\((3, 4, 1)\)\((3, 4, 2)\)\((4, 2, 1)\)\((4, 2, 3)\)\((4, 3, 1)\)\((4, 3, 2)\)

数据范围与提示

子任务 1(5 分):\(n \le 10 , m \le 100\)

子任务 2(11 分):\(n \le 50 , m \le 100\)

子任务 3(8 分):\(n \le 100\,000\) ,每个交叉路口至多作为两条双向道路的端点。

子任务 4(10 分):\(n \le 1\,000\) ,在路网中不存在环。

存在环是指存在一个长度为 \(k\) (\(k\ge 3\)) 的交叉路口序列 \(v_1, v_2, \ldots v_k\) ,序列中的路口编号两两不同,且对于 \(i\)\(1\)\(k-1\) ,有一条双向道路直接连接路口 \(v_i\)\(v_{i+1}\) ,且有一条双向道路直接连接路口 \(v_k\)\(v_1\)

子任务 5(13 分):\(n \le 100\,000\) ,在路网中不存在环。

子任务 6(15 分):\(n \le 1\,000\) ,对于每个交叉路口,至多被一个环包含。

子任务 7(20 分):\(n \le 100\,000\) ,对于每个交叉路口,至多被一个环包含。

子任务 8(8 分):\(n \le 1\,000, m \le 2\,000\)

子任务 9(10 分):\(n \le 100\,000, m \le 200\,000\)

题解

考场上就多写了个树的,后来发现圆方树的做法好简单啊,居然没想出来qwq
求出点双并且建出圆方树后,假设确定了 \(s\)\(f\) ,那么 \(c\) 的情况就是 \(s\)\(f\) 的路径上的点相邻的不同的圆点的个数
令每个方点的权值等于其度数,圆点的权值等于 \(-1\) ,那么 \(c\) 的数量就等于 \(s\)\(f\) 路径上的权值和
所以就可以一个树形dp,线性统计答案了

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=100000+10,MAXM=200000+10;
int n,m,e,to[MAXM<<2],nex[MAXM<<2],out[MAXM<<2],beg[MAXN<<1],val[MAXN<<1],Visit_Num,DFN[MAXN],LOW[MAXN],cnt,Be[MAXN],size[MAXN<<1],vis[MAXN<<1],bel[MAXN<<1],all[MAXN<<1],clk;
ll ans;
std::stack<int> s;
std::vector<int> point[MAXN];
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void insert(int x,int y)
{
    to[++e]=y;
    nex[e]=beg[x];
    out[e]=x;
    beg[x]=e;
}
inline void Tarjan(int x,int f)
{
    DFN[x]=LOW[x]=++Visit_Num;bel[x]=clk;all[clk]++;
    for(register int i=beg[x];i;i=nex[i])
        if(to[i]==f)continue;
        else if(!DFN[to[i]])
        {
            s.push(i);
            Tarjan(to[i],x);
            chkmin(LOW[x],LOW[to[i]]);
            if(LOW[to[i]]>=DFN[x])
            {
                int temp;++cnt;
                do{
                    temp=s.top();
                    s.pop();
                    if(Be[out[temp]]!=cnt)
                    {
                        Be[out[temp]]=cnt;
                        point[cnt].push_back(out[temp]);
                    }
                    if(Be[to[temp]]!=cnt)
                    {
                        Be[to[temp]]=cnt;
                        point[cnt].push_back(to[temp]);
                    }
                }while(out[temp]!=x||to[temp]!=to[i]);
            }
        }
        else if(DFN[to[i]]<DFN[x])s.push(i),chkmin(LOW[x],DFN[to[i]]);
}
inline void dfs(int x,int f)
{
    vis[x]=1;
    for(register int i=beg[x];i;i=nex[i])
        if(to[i]==f)continue;
        else
        {
            dfs(to[i],x);
            ans+=1ll*val[x]*size[x]*size[to[i]];
            size[x]+=size[to[i]];
        }
    if(x<=n)size[x]++;
    if(x<=n)ans+=1ll*val[x]*(size[x]-1)*(all[bel[x]]-size[x])-all[bel[x]]+1;
    else ans+=1ll*val[x]*size[x]*(all[bel[x]]-size[x]);
}
int main()
{
    read(n);read(m);
    for(register int i=1;i<=m;++i)
    {
        int u,v;read(u);read(v);
        insert(u,v);insert(v,u);
    }
    for(register int i=1;i<=n;++i)
        if(!DFN[i])clk++,Tarjan(i,0);
    e=0;memset(beg,0,sizeof(beg));
    for(register int i=1;i<=n;++i)val[i]=-1;
    for(register int i=1;i<=cnt;++i)
        for(register int j=0,lt=point[i].size();j<lt;++j)
        {
            bel[i+n]=bel[point[i][j]];
            insert(i+n,point[i][j]);
            insert(point[i][j],i+n);
            val[i+n]++;
        }
    for(register int i=1;i<=n;++i)
        if(!vis[i])dfs(i,0);
    write(ans<<1,'\n');
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hongyj/p/9544520.html
今日推荐