zoukankan      html  css  js  c++  java
  • 【刷题】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 eq 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) ((kge 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='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')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,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    【转】PowerManager 与 WakeLock
    【转】设计模式总结之模式分类
    【转】一篇文章,教你学会Git
    【转】Iconfont
    【转】码云source tree 提交超过100m 为什么大文件推不上去
    各 Android 平台版本支持的 API 级别
    【转】Android进程机制
    【转】数据库CRUD操作
    【转】数据库--视图的基本概念以及作用
    动态规划的两种形式
  • 原文地址:https://www.cnblogs.com/hongyj/p/9544520.html
Copyright © 2011-2022 走看看