LOJ2587:[APIO2018]铁人两项——题解
https://loj.ac/problem/2587#submit_code

(题面来自LOJ)
考试时候发觉树很可做,并且写了一个dp骗到了树的分。
苦于不会圆方树……现在回来发现这题还是很可做的!
先套路套圆方树,然后思考路径条数如何计算。
一个显然的想法:从一个点双-> 一个点双->……-> 一个点双,条数没准就是每个点双的大小!
于是我们能够想到方点的权值为点双的大小。
当然注意到我们选择的起点/终点以及每个点双之间相邻的切点只能走一次,为了去重,我们把圆点权值设为-1。
则任取起点s,终点t的情况就是s->t的路径上所有点的权值和。
当然此时我们可以用dp做,但是我当时的代码没拷于是现在我也忘了怎么做了,我们换一种大家普遍(我看其他人代码)的一种方法。
我们求出来每个点u,有多少条路径通过它即可,具体dp可以看我的代码注释。
以及注意这题每个结点之间至多有一条,而不是至少!坑死我了。
#include<cmath>
#include<queue>
#include<stack>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+;
const int M=N*;
inline int read(){
int X=,w=;char ch=;
while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
while(isdigit(ch))X=(X<<)+(X<<)+(ch^),ch=getchar();
return w?-X:X;
}
struct node{
int u[M],v[M],nxt[M];
int cnt,head[N];
void init(){
cnt=;
memset(head,,sizeof(head));
}
void add(int U,int V){
u[++cnt]=U;v[cnt]=V;nxt[cnt]=head[U];head[U]=cnt;
}
}e,g;
int n,m;
int dfn[N],low[N],to[N],t,l;
ll w[N];
stack<int>q;
void tarjan(int u,int f){
dfn[u]=low[u]=++t;
for(int i=g.head[u];i;i=g.nxt[i]){
int v=g.v[i];
if(!dfn[v]){
q.push(i);
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
int num;l++;
do{
num=q.top();q.pop();
int uu=g.u[num],vv=g.v[num];
if(to[uu]!=l){
to[uu]=l;
e.add(uu,l+n);e.add(l+n,uu);
w[l+n]++;w[uu]=-;
}
if(to[vv]!=l){
to[vv]=l;
e.add(vv,l+n);e.add(l+n,vv);
w[l+n]++;w[vv]=-;
}
}while(num!=i);
}
}else if(low[u]>dfn[v]&&f!=v){
q.push(i);
low[u]=dfn[v];
}
}
}
bool vis[N];
ll ans,size[N],sum;
void dfs1(int u,int f){
vis[u]=;
size[u]=(u<=n);
for(int i=e.head[u];i;i=e.nxt[i]){
int v=e.v[i];
if(v==f)continue;
dfs1(v,u);
size[u]+=size[v];
}
}
void dfs2(int u,int f){
for(int i=e.head[u];i;i=e.nxt[i]){
int v=e.v[i];
if(v==f)continue;
dfs2(v,u);
ans+=w[u]*size[v]*(sum-size[v]);
//以v根树为起点和以v根树补集为终点
//已经暗含了当u合法的时候,以u为终点的路径
}
ans+=w[u]*(sum-size[u])*size[u];
//以u根树补集为起点和以u根树为终点
if(u<=n)ans+=w[u]*(sum-);//以u为起点的路径
}
int main(){
n=read(),m=read();
for(int i=;i<=m;i++){
int u=read(),v=read();
g.add(u,v);g.add(v,u);
}
for(int i=;i<=n;i++)
if(!dfn[i])tarjan(i,);
for(int i=;i<=n;i++){
if(!vis[i]){
dfs1(i,);sum=size[i];dfs2(i,);
}
}
printf("%lld\n",ans);
return ;
}
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++
LOJ2587:[APIO2018]铁人两项——题解的更多相关文章
- [APIO2018]铁人两项 --- 圆方树
[APIO2018] 铁人两项 题目大意: 给定一张图,问有多少三元组(a,b,c)(a,b,c 互不相等)满足存在一条点不重复的以a为起点,经过b,终点为c的路径 如果你不会圆方树 ------- ...
- [APIO2018]铁人两项——圆方树+树形DP
题目链接: [APIO2018]铁人两项 对于点双连通分量有一个性质:在同一个点双里的三个点$a,b,c$,一定存在一条从$a$到$c$的路径经过$b$且经过的点只被经过一次. 那么我们建出原图的圆方 ...
- [APIO2018]铁人两项 [圆方树模板]
把这个图缩成圆方树,把方点的权值设成-1,圆点的权值设成点双的size,算 经过这个点的路径的数量*这个点的点权 的和即是答案. #include <iostream> #include ...
- [APIO2018]铁人两项(圆方树)
过了14个月再重新看这题,发现圆方树从来就没有写过.然后写了这题发现自己APIO2018打铁的原因竟然是没开long long,将树的部分的O(n)写挂了(爆int),毕竟去年APIO时我啥都不会,连 ...
- 2019.03.29 bzoj5463: [APIO2018] 铁人两项(圆方树+树形dp)
传送门 题意简述:给你一张无向图,问你满足存在从a−>b−>ca->b->ca−>b−>c且不经过重复节点的路径的有序点对(a,b,c)(a,b,c)(a,b,c) ...
- LOJ.2587.[APIO2018]铁人两项Duathlon(圆方树)
题目链接 LOJ 洛谷P4630 先对这张图建圆方树. 对于S->T这条(些)路径,其对答案的贡献为可能经过的所有点数,那么我们把方点权值设为联通分量的大小,可以直接去求树上路径权值和. 因为两 ...
- [BZOJ5463][APIO2018]铁人两项:Tarjan+圆方树
分析 根据题目中的要求,从\(s\)出发前往\(f\)一定可以,并且只可能经过这两个结点所在的点双连通分量和它们之间的点双连通分量,因此切换点\(c\)只能从这些点中选取. 建出圆方树后,因为圆方树上 ...
- 洛谷P4630 [APIO2018]铁人两项 [广义圆方树]
传送门 又学会了一个新东西好开心呢~ 思路 显然,假如枚举了起始点\(x\)和终止点\(y\),中转点就必须在它们之间的简单路径上. 不知为何想到了圆方树,可以发现,如果把方点的权值记为双联通分量的大 ...
- [BZOJ5463] [APIO2018] 铁人两项
题目链接 LOJ. BZOJ. Solution 先建圆方树. 我们考虑暴力,枚举一个点对,我们枚举的点都是圆点,然后统计中间那个点可以取的位置的数量,加起来就是答案. 那么怎么统计呢,我们对于每个点 ...
随机推荐
- spark history server
参考:http://blog.csdn.net/lsshlsw/article/details/44786575 为什么需要historyServer? 在运行Spark Application的时候 ...
- Java图片转字符
很久都没有更新博客了,昨天下午一个朋友问我能不能将一张图片转换成字符画,然后我想我这个朋友不知道,也许有的朋友以不知道,我就简单的分享一下 package com.xsl.zhuanhuan; imp ...
- RabbitMQ基础教程之Spring&JavaConfig使用篇
RabbitMQ基础教程之Spring使用篇 相关博文,推荐查看: RabbitMq基础教程之安装与测试 RabbitMq基础教程之基本概念 RabbitMQ基础教程之基本使用篇 RabbitMQ基础 ...
- 【selenium】selenium全分享
第一节:selenium基础 [http://note.youdao.com/noteshare?id=43603fb53593bfc15c28bc358a3fa6ec] 目录: selenium简介 ...
- jstat命令
jstat命令使用 jstat命令可以查看堆内存各部分的使用量,以及加载类的数量.命令的格式如下: jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数] 注意:使用的jdk版本是 ...
- 【Python 开发】第二篇 :Python安装
一.python3.x安装 1)由于centos7原本就安装了Python2,而且这个Python2不能被删除,因为有很多系统命令,比如yum都要用到. 官网:https://www.python.o ...
- C++字符串拼接和输入
一 .char类型字符串以空字符结尾 1.以空字符结尾,空字符被写作\0,其ASCII码为0,用来标记字符串的结尾. char dog[4]={'a','b','c','d'} //不是一个字符串 ...
- Notes of the scrum meeting before publishing(12.19)
meeting time:18:30~20:30p.m.,December 19th,2013 meeting place:3号公寓一层 attendees: 顾育豪 ...
- windows编程了解
文章:浅谈Windows API编程 (这个经典)
- JavaBean中DAO设计模式简介
一.信息系统的开发架构 客户层-------显示层-------业务层---------数据层---------数据库 1.客户层:客户层就是客户端,简单的来说就是浏览器. 2.显示层:JSP/Ser ...